1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 /** 18 * @author Igor V. Stolyarov 19 * @version $Revision$ 20 */ 21 22 package java.awt.image; 23 24 import java.awt.Transparency; 25 import java.awt.color.ColorSpace; 26 import java.math.BigInteger; 27 28 import org.apache.harmony.awt.internal.nls.Messages; 29 30 /** 31 * The Class IndexColorModel represents a color model in which the color values 32 * of the pixels are read from a palette. 33 * 34 * @since Android 1.0 35 */ 36 public class IndexColorModel extends ColorModel { 37 38 /** 39 * The color map. 40 */ 41 private int colorMap[]; // Color Map 42 43 /** 44 * The map size. 45 */ 46 private int mapSize; // Color Map size 47 48 /** 49 * The transparent index. 50 */ 51 private int transparentIndex; // Index of fully transparent pixel 52 53 /** 54 * The gray palette. 55 */ 56 private boolean grayPalette; // Color Model has Color Map with Gray Pallete 57 58 /** 59 * The valid bits. 60 */ 61 private BigInteger validBits; // Specify valid Color Map values 62 63 /** 64 * The Constant CACHESIZE. 65 */ 66 private static final int CACHESIZE = 20; // Cache size. Cache used for 67 68 // improving performace of selection 69 // nearest color in Color Map 70 71 /** 72 * The cachetable. 73 */ 74 private final int cachetable[] = new int[CACHESIZE * 2]; // Cache table - 75 76 // used for 77 78 // storing RGB values and that appropriate indices 79 // in the Color Map 80 81 /** 82 * The next insert idx. 83 */ 84 private int nextInsertIdx = 0; // Next index for insertion into Cache table 85 86 /** 87 * The total inserted. 88 */ 89 private int totalInserted = 0; // Number of inserted values into Cache table 90 91 /** 92 * Instantiates a new index color model. 93 * 94 * @param bits 95 * the array of component masks. 96 * @param size 97 * the size of the color map. 98 * @param cmap 99 * the array that gives the color mapping. 100 * @param start 101 * the start index of the color mapping data within the cmap 102 * array. 103 * @param transferType 104 * the transfer type (primitive java type to use for the 105 * components). 106 * @param validBits 107 * a list of which bits represent valid colormap values, or null 108 * if all are valid. 109 * @throws IllegalArgumentException 110 * if the size of the color map is less than one. 111 */ 112 public IndexColorModel(int bits, int size, int cmap[], int start, int transferType, 113 BigInteger validBits) { 114 115 super(bits, IndexColorModel.createBits(true), ColorSpace.getInstance(ColorSpace.CS_sRGB), 116 true, false, Transparency.OPAQUE, validateTransferType(transferType)); 117 118 if (size < 1) { 119 // awt.264=Size of the color map is less than 1 120 throw new IllegalArgumentException(Messages.getString("awt.264")); //$NON-NLS-1$ 121 } 122 123 mapSize = size; 124 colorMap = new int[mapSize]; 125 transparentIndex = -1; 126 127 if (validBits != null) { 128 for (int i = 0; i < mapSize; i++) { 129 if (!validBits.testBit(i)) { 130 this.validBits = validBits; 131 } 132 break; 133 } 134 } 135 136 transparency = Transparency.OPAQUE; 137 int alphaMask = 0xff000000; 138 int alpha = 0; 139 140 for (int i = 0; i < mapSize; i++, start++) { 141 colorMap[i] = cmap[start]; 142 alpha = cmap[start] & alphaMask; 143 144 if (alpha == alphaMask) { 145 continue; 146 } 147 if (alpha == 0) { 148 if (transparentIndex < 0) { 149 transparentIndex = i; 150 } 151 if (transparency == Transparency.OPAQUE) { 152 transparency = Transparency.BITMASK; 153 } 154 } else if (alpha != alphaMask && transparency != Transparency.TRANSLUCENT) { 155 transparency = Transparency.TRANSLUCENT; 156 } 157 158 } 159 checkPalette(); 160 161 } 162 163 /** 164 * Instantiates a new index color model. 165 * 166 * @param bits 167 * the array of component masks. 168 * @param size 169 * the size of the color map. 170 * @param cmap 171 * the array that gives the color mapping. 172 * @param start 173 * the start index of the color mapping data within the cmap 174 * array. 175 * @param hasalpha 176 * whether this color model uses alpha. 177 * @param trans 178 * the transparency supported, @see java.awt.Transparency. 179 * @param transferType 180 * the transfer type (primitive java type to use for the 181 * components). 182 * @throws IllegalArgumentException 183 * if the size of the color map is less than one. 184 */ 185 public IndexColorModel(int bits, int size, int cmap[], int start, boolean hasalpha, int trans, 186 int transferType) { 187 188 super(bits, IndexColorModel.createBits(hasalpha || (trans >= 0)), ColorSpace 189 .getInstance(ColorSpace.CS_sRGB), (hasalpha || (trans >= 0)), false, 190 Transparency.OPAQUE, validateTransferType(transferType)); 191 192 if (size < 1) { 193 // awt.264=Size of the color map is less than 1 194 throw new IllegalArgumentException(Messages.getString("awt.264")); //$NON-NLS-1$ 195 } 196 197 mapSize = size; 198 colorMap = new int[mapSize]; 199 if (trans >= 0 && trans < mapSize) { 200 transparentIndex = trans; 201 transparency = Transparency.BITMASK; 202 } else { 203 transparentIndex = -1; 204 transparency = Transparency.OPAQUE; 205 } 206 207 int alphaMask = 0xff000000; 208 int alpha = 0; 209 210 for (int i = 0; i < mapSize; i++, start++) { 211 if (transparentIndex == i) { 212 colorMap[i] = cmap[start] & 0x00ffffff; 213 continue; 214 } 215 if (hasalpha) { 216 alpha = cmap[start] & alphaMask; 217 colorMap[i] = cmap[start]; 218 219 if (alpha == alphaMask) { 220 continue; 221 } 222 if (alpha == 0) { 223 if (trans < 0) { 224 trans = i; 225 } 226 if (transparency == Transparency.OPAQUE) { 227 transparency = Transparency.BITMASK; 228 } 229 } else if (alpha != 0 && transparency != Transparency.TRANSLUCENT) { 230 transparency = Transparency.TRANSLUCENT; 231 } 232 } else { 233 colorMap[i] = alphaMask | cmap[start]; 234 } 235 } 236 checkPalette(); 237 238 } 239 240 /** 241 * Instantiates a new index color model by building the color map from 242 * arrays of red, green, blue, and alpha values. 243 * 244 * @param bits 245 * the array of component masks. 246 * @param size 247 * the size of the color map. 248 * @param r 249 * the array giving the red components of the entries in the 250 * color map. 251 * @param g 252 * the array giving the green components of the entries in the 253 * color map. 254 * @param b 255 * the array giving the blue components of the entries in the 256 * color map. 257 * @param a 258 * the array giving the alpha components of the entries in the 259 * color map. 260 * @throws IllegalArgumentException 261 * if the size of the color map is less than one. 262 * @throws ArrayIndexOutOfBoundsException 263 * if the size of one of the component arrays is less than the 264 * size of the color map. 265 */ 266 public IndexColorModel(int bits, int size, byte r[], byte g[], byte b[], byte a[]) { 267 268 super(bits, IndexColorModel.createBits(true), ColorSpace.getInstance(ColorSpace.CS_sRGB), 269 true, false, Transparency.OPAQUE, validateTransferType(ColorModel 270 .getTransferType(bits))); 271 272 createColorMap(size, r, g, b, a, -1); 273 checkPalette(); 274 } 275 276 /** 277 * Instantiates a new index color model by building the color map from 278 * arrays of red, green, and blue values. 279 * 280 * @param bits 281 * the array of component masks. 282 * @param size 283 * the size of the color map. 284 * @param r 285 * the array giving the red components of the entries in the 286 * color map. 287 * @param g 288 * the array giving the green components of the entries in the 289 * color map. 290 * @param b 291 * the array giving the blue components of the entries in the 292 * color map. 293 * @param trans 294 * the transparency supported, @see java.awt.Transparency. 295 * @throws IllegalArgumentException 296 * if the size of the color map is less than one. 297 * @throws ArrayIndexOutOfBoundsException 298 * if the size of one of the component arrays is less than the 299 * size of the color map. 300 */ 301 public IndexColorModel(int bits, int size, byte r[], byte g[], byte b[], int trans) { 302 303 super(bits, IndexColorModel.createBits((trans >= 0)), ColorSpace 304 .getInstance(ColorSpace.CS_sRGB), (trans >= 0), false, Transparency.OPAQUE, 305 validateTransferType(ColorModel.getTransferType(bits))); 306 307 createColorMap(size, r, g, b, null, trans); 308 checkPalette(); 309 } 310 311 /** 312 * Instantiates a new index color model by building the color map from 313 * arrays of red, green, and blue values. 314 * 315 * @param bits 316 * the array of component masks. 317 * @param size 318 * the size of the color map. 319 * @param r 320 * the array giving the red components of the entries in the 321 * color map. 322 * @param g 323 * the array giving the green components of the entries in the 324 * color map. 325 * @param b 326 * the array giving the blue components of the entries in the 327 * color map. 328 * @throws IllegalArgumentException 329 * if the size of the color map is less than one. 330 * @throws ArrayIndexOutOfBoundsException 331 * if the size of one of the component arrays is less than the 332 * size of the color map. 333 */ 334 public IndexColorModel(int bits, int size, byte r[], byte g[], byte b[]) { 335 super(bits, IndexColorModel.createBits(false), ColorSpace.getInstance(ColorSpace.CS_sRGB), 336 false, false, Transparency.OPAQUE, validateTransferType(ColorModel 337 .getTransferType(bits))); 338 339 createColorMap(size, r, g, b, null, -1); 340 checkPalette(); 341 } 342 343 /** 344 * Instantiates a new index color model. 345 * 346 * @param bits 347 * the array of component masks. 348 * @param size 349 * the size of the color map. 350 * @param cmap 351 * the array that gives the color mapping. 352 * @param start 353 * the start index of the color mapping data within the cmap 354 * array. 355 * @param hasalpha 356 * whether this color model uses alpha. 357 * @param trans 358 * the transparency supported, @see java.awt.Transparency. 359 * @throws IllegalArgumentException 360 * if the size of the color map is less than one. 361 */ 362 public IndexColorModel(int bits, int size, byte cmap[], int start, boolean hasalpha, int trans) { 363 364 super(bits, IndexColorModel.createBits(hasalpha || (trans >= 0)), ColorSpace 365 .getInstance(ColorSpace.CS_sRGB), (hasalpha || (trans >= 0)), false, 366 Transparency.OPAQUE, validateTransferType(ColorModel.getTransferType(bits))); 367 368 if (size < 1) { 369 // awt.264=Size of the color map is less than 1 370 throw new IllegalArgumentException(Messages.getString("awt.264")); //$NON-NLS-1$ 371 } 372 373 mapSize = size; 374 colorMap = new int[mapSize]; 375 transparentIndex = -1; 376 377 transparency = Transparency.OPAQUE; 378 int alpha = 0xff000000; 379 380 for (int i = 0; i < mapSize; i++) { 381 colorMap[i] = (cmap[start++] & 0xff) << 16 | (cmap[start++] & 0xff) << 8 382 | (cmap[start++] & 0xff); 383 if (trans == i) { 384 if (transparency == Transparency.OPAQUE) { 385 transparency = Transparency.BITMASK; 386 } 387 if (hasalpha) { 388 start++; 389 } 390 continue; 391 } 392 if (hasalpha) { 393 alpha = cmap[start++] & 0xff; 394 if (alpha == 0) { 395 if (transparency == Transparency.OPAQUE) { 396 transparency = Transparency.BITMASK; 397 if (trans < 0) { 398 trans = i; 399 } 400 } 401 } else { 402 if (alpha != 0xff && transparency != Transparency.TRANSLUCENT) { 403 transparency = Transparency.TRANSLUCENT; 404 } 405 } 406 alpha <<= 24; 407 } 408 colorMap[i] |= alpha; 409 } 410 411 if (trans >= 0 && trans < mapSize) { 412 transparentIndex = trans; 413 } 414 checkPalette(); 415 416 } 417 418 /** 419 * Instantiates a new index color model. 420 * 421 * @param bits 422 * the array of component masks. 423 * @param size 424 * the size of the color map. 425 * @param cmap 426 * the array that gives the color mapping. 427 * @param start 428 * the start index of the color mapping data within the cmap 429 * array. 430 * @param hasalpha 431 * whether this color model uses alpha. 432 * @throws IllegalArgumentException 433 * if the size of the color map is less than one. 434 */ 435 public IndexColorModel(int bits, int size, byte cmap[], int start, boolean hasalpha) { 436 437 this(bits, size, cmap, start, hasalpha, -1); 438 } 439 440 @Override 441 public Object getDataElements(int[] components, int offset, Object pixel) { 442 int rgb = (components[offset] << 16) | (components[offset + 1]) << 8 443 | components[offset + 2]; 444 if (hasAlpha) { 445 rgb |= components[offset + 3] << 24; 446 } else { 447 rgb |= 0xff000000; 448 } 449 return getDataElements(rgb, pixel); 450 } 451 452 @Override 453 public synchronized Object getDataElements(int rgb, Object pixel) { 454 int red = (rgb >> 16) & 0xff; 455 int green = (rgb >> 8) & 0xff; 456 int blue = rgb & 0xff; 457 int alpha = rgb >>> 24; 458 int pixIdx = 0; 459 460 for (int i = 0; i < totalInserted; i++) { 461 int idx = i * 2; 462 if (rgb == cachetable[idx]) { 463 return createDataObject(cachetable[idx + 1], pixel); 464 } 465 } 466 467 if (!hasAlpha && grayPalette) { 468 int grey = (red * 77 + green * 150 + blue * 29 + 128) >>> 8; 469 int minError = 255; 470 int error = 0; 471 472 for (int i = 0; i < mapSize; i++) { 473 error = Math.abs((colorMap[i] & 0xff) - grey); 474 if (error < minError) { 475 pixIdx = i; 476 if (error == 0) { 477 break; 478 } 479 minError = error; 480 } 481 } 482 } else if (alpha == 0 && transparentIndex > -1) { 483 pixIdx = transparentIndex; 484 } else { 485 int minAlphaError = 255; 486 int minError = 195075; // 255^2 + 255^2 + 255^2 487 int alphaError; 488 int error = 0; 489 490 for (int i = 0; i < mapSize; i++) { 491 int pix = colorMap[i]; 492 if (rgb == pix) { 493 pixIdx = i; 494 break; 495 } 496 alphaError = Math.abs(alpha - (pix >>> 24)); 497 if (alphaError <= minAlphaError) { 498 minAlphaError = alphaError; 499 500 int buf = ((pix >> 16) & 0xff) - red; 501 error = buf * buf; 502 503 if (error < minError) { 504 buf = ((pix >> 8) & 0xff) - green; 505 error += buf * buf; 506 507 if (error < minError) { 508 buf = (pix & 0xff) - blue; 509 error += buf * buf; 510 511 if (error < minError) { 512 pixIdx = i; 513 minError = error; 514 } 515 } 516 } 517 } 518 } 519 } 520 521 cachetable[nextInsertIdx] = rgb; 522 cachetable[nextInsertIdx + 1] = pixIdx; 523 524 nextInsertIdx = (nextInsertIdx + 2) % (CACHESIZE * 2); 525 if (totalInserted < CACHESIZE) { 526 totalInserted++; 527 } 528 529 return createDataObject(pixIdx, pixel); 530 } 531 532 /** 533 * Converts an image from indexed to RGB format. 534 * 535 * @param raster 536 * the raster containing the source image. 537 * @param forceARGB 538 * whether to use the default RGB color model. 539 * @return the buffered image. 540 * @throws IllegalArgumentException 541 * if the raster is not compatible with this color model. 542 */ 543 public BufferedImage convertToIntDiscrete(Raster raster, boolean forceARGB) { 544 545 if (!isCompatibleRaster(raster)) { 546 // awt.265=The raster argument is not compatible with this 547 // IndexColorModel 548 throw new IllegalArgumentException(Messages.getString("awt.265")); //$NON-NLS-1$ 549 } 550 551 ColorModel model; 552 if (forceARGB || transparency == Transparency.TRANSLUCENT) { 553 model = ColorModel.getRGBdefault(); 554 } else if (transparency == Transparency.BITMASK) { 555 model = new DirectColorModel(25, 0x00ff0000, 0x0000ff00, 0x000000ff, 0x01000000); 556 } else { 557 model = new DirectColorModel(24, 0x00ff0000, 0x0000ff00, 0x000000ff); 558 } 559 560 int w = raster.getWidth(); 561 int h = raster.getHeight(); 562 563 WritableRaster distRaster = model.createCompatibleWritableRaster(w, h); 564 565 int minX = raster.getMinX(); 566 int minY = raster.getMinY(); 567 568 Object obj = null; 569 int pixels[] = null; 570 571 for (int i = 0; i < h; i++, minY++) { 572 obj = raster.getDataElements(minX, minY, w, 1, obj); 573 if (obj instanceof byte[]) { 574 byte ba[] = (byte[])obj; 575 if (pixels == null) { 576 pixels = new int[ba.length]; 577 } 578 for (int j = 0; j < ba.length; j++) { 579 pixels[j] = colorMap[ba[j] & 0xff]; 580 } 581 } else if (obj instanceof short[]) { 582 short sa[] = (short[])obj; 583 if (pixels == null) { 584 pixels = new int[sa.length]; 585 } 586 for (int j = 0; j < sa.length; j++) { 587 pixels[j] = colorMap[sa[j] & 0xffff]; 588 } 589 } 590 if (obj instanceof int[]) { 591 int ia[] = (int[])obj; 592 if (pixels == null) { 593 pixels = new int[ia.length]; 594 } 595 for (int j = 0; j < ia.length; j++) { 596 pixels[j] = colorMap[ia[j]]; 597 } 598 } 599 600 distRaster.setDataElements(0, i, w, 1, pixels); 601 } 602 603 return new BufferedImage(model, distRaster, false, null); 604 } 605 606 /** 607 * Gets the valid pixels. 608 * 609 * @return the valid pixels. 610 */ 611 public BigInteger getValidPixels() { 612 return validBits; 613 } 614 615 @Override 616 public String toString() { 617 // The output format based on 1.5 release behaviour. 618 // It could be reveled such way: 619 // BufferedImage bi = new BufferedImage(1, 1, 620 // BufferedImage.TYPE_BYTE_INDEXED); 621 // ColorModel cm = bi.getColorModel(); 622 // System.out.println(cm.toString()); 623 String str = "IndexColorModel: #pixel_bits = " + pixel_bits + //$NON-NLS-1$ 624 " numComponents = " + numComponents + " color space = " + cs + //$NON-NLS-1$ //$NON-NLS-2$ 625 " transparency = "; //$NON-NLS-1$ 626 627 if (transparency == Transparency.OPAQUE) { 628 str = str + "Transparency.OPAQUE"; //$NON-NLS-1$ 629 } else if (transparency == Transparency.BITMASK) { 630 str = str + "Transparency.BITMASK"; //$NON-NLS-1$ 631 } else { 632 str = str + "Transparency.TRANSLUCENT"; //$NON-NLS-1$ 633 } 634 635 str = str + " transIndex = " + transparentIndex + " has alpha = " + //$NON-NLS-1$ //$NON-NLS-2$ 636 hasAlpha + " isAlphaPre = " + isAlphaPremultiplied; //$NON-NLS-1$ 637 638 return str; 639 } 640 641 @Override 642 public int[] getComponents(Object pixel, int components[], int offset) { 643 int pixIdx = -1; 644 if (pixel instanceof byte[]) { 645 byte ba[] = (byte[])pixel; 646 pixIdx = ba[0] & 0xff; 647 } else if (pixel instanceof short[]) { 648 short sa[] = (short[])pixel; 649 pixIdx = sa[0] & 0xffff; 650 } else if (pixel instanceof int[]) { 651 int ia[] = (int[])pixel; 652 pixIdx = ia[0]; 653 } else { 654 // awt.219=This transferType is not supported by this color model 655 throw new UnsupportedOperationException(Messages.getString("awt.219")); //$NON-NLS-1$ 656 } 657 658 return getComponents(pixIdx, components, offset); 659 } 660 661 @Override 662 public WritableRaster createCompatibleWritableRaster(int w, int h) { 663 WritableRaster raster; 664 if (pixel_bits == 1 || pixel_bits == 2 || pixel_bits == 4) { 665 raster = Raster.createPackedRaster(DataBuffer.TYPE_BYTE, w, h, 1, pixel_bits, null); 666 } else if (pixel_bits <= 8) { 667 raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, w, h, 1, null); 668 } else if (pixel_bits <= 16) { 669 raster = Raster.createInterleavedRaster(DataBuffer.TYPE_USHORT, w, h, 1, null); 670 } else { 671 // awt.266=The number of bits in a pixel is greater than 16 672 throw new UnsupportedOperationException(Messages.getString("awt.266")); //$NON-NLS-1$ 673 } 674 675 return raster; 676 } 677 678 @Override 679 public boolean isCompatibleSampleModel(SampleModel sm) { 680 if (sm == null) { 681 return false; 682 } 683 684 if (!(sm instanceof MultiPixelPackedSampleModel) && !(sm instanceof ComponentSampleModel)) { 685 return false; 686 } 687 688 if (sm.getTransferType() != transferType) { 689 return false; 690 } 691 if (sm.getNumBands() != 1) { 692 return false; 693 } 694 695 return true; 696 } 697 698 @Override 699 public SampleModel createCompatibleSampleModel(int w, int h) { 700 if (pixel_bits == 1 || pixel_bits == 2 || pixel_bits == 4) { 701 return new MultiPixelPackedSampleModel(DataBuffer.TYPE_BYTE, w, h, pixel_bits); 702 } 703 int bandOffsets[] = new int[1]; 704 bandOffsets[0] = 0; 705 return new ComponentSampleModel(transferType, w, h, 1, w, bandOffsets); 706 707 } 708 709 @Override 710 public boolean isCompatibleRaster(Raster raster) { 711 int sampleSize = raster.getSampleModel().getSampleSize(0); 712 return (raster.getTransferType() == transferType && raster.getNumBands() == 1 && (1 << sampleSize) >= mapSize); 713 } 714 715 @Override 716 public int getDataElement(int components[], int offset) { 717 int rgb = (components[offset] << 16) | (components[offset + 1]) << 8 718 | components[offset + 2]; 719 720 if (hasAlpha) { 721 rgb |= components[offset + 3] << 24; 722 } else { 723 rgb |= 0xff000000; 724 } 725 726 int pixel; 727 728 switch (transferType) { 729 case DataBuffer.TYPE_BYTE: 730 byte ba[] = (byte[])getDataElements(rgb, null); 731 pixel = ba[0] & 0xff; 732 break; 733 case DataBuffer.TYPE_USHORT: 734 short sa[] = (short[])getDataElements(rgb, null); 735 pixel = sa[0] & 0xffff; 736 break; 737 default: 738 // awt.267=The transferType is invalid 739 throw new UnsupportedOperationException(Messages.getString("awt.267")); //$NON-NLS-1$ 740 } 741 742 return pixel; 743 } 744 745 /** 746 * Gets the color map. 747 * 748 * @param rgb 749 * the destination array where the color map is written. 750 */ 751 public final void getRGBs(int rgb[]) { 752 System.arraycopy(colorMap, 0, rgb, 0, mapSize); 753 } 754 755 /** 756 * Gets the red component of the color map. 757 * 758 * @param r 759 * the destination array. 760 */ 761 public final void getReds(byte r[]) { 762 for (int i = 0; i < mapSize; i++) { 763 r[i] = (byte)(colorMap[i] >> 16); 764 } 765 } 766 767 /** 768 * Gets the green component of the color map. 769 * 770 * @param g 771 * the destination array. 772 */ 773 public final void getGreens(byte g[]) { 774 for (int i = 0; i < mapSize; i++) { 775 g[i] = (byte)(colorMap[i] >> 8); 776 } 777 } 778 779 /** 780 * Gets the blue component of the color map. 781 * 782 * @param b 783 * the destination array. 784 */ 785 public final void getBlues(byte b[]) { 786 for (int i = 0; i < mapSize; i++) { 787 b[i] = (byte)colorMap[i]; 788 } 789 } 790 791 /** 792 * Gets the alpha component of the color map. 793 * 794 * @param a 795 * the destination array. 796 */ 797 public final void getAlphas(byte a[]) { 798 for (int i = 0; i < mapSize; i++) { 799 a[i] = (byte)(colorMap[i] >> 24); 800 } 801 } 802 803 @Override 804 public int[] getComponents(int pixel, int components[], int offset) { 805 if (components == null) { 806 components = new int[offset + numComponents]; 807 } 808 809 components[offset + 0] = getRed(pixel); 810 components[offset + 1] = getGreen(pixel); 811 components[offset + 2] = getBlue(pixel); 812 if (hasAlpha && (components.length - offset) > 3) { 813 components[offset + 3] = getAlpha(pixel); 814 } 815 816 return components; 817 } 818 819 /** 820 * Checks if the specified pixel is valid for this color model. 821 * 822 * @param pixel 823 * the pixel. 824 * @return true, if the pixel is valid. 825 */ 826 public boolean isValid(int pixel) { 827 if (validBits == null) { 828 return (pixel >= 0 && pixel < mapSize); 829 } 830 return (pixel < mapSize && validBits.testBit(pixel)); 831 } 832 833 @Override 834 public final int getRed(int pixel) { 835 return (colorMap[pixel] >> 16) & 0xff; 836 } 837 838 @Override 839 public final int getRGB(int pixel) { 840 return colorMap[pixel]; 841 } 842 843 @Override 844 public final int getGreen(int pixel) { 845 return (colorMap[pixel] >> 8) & 0xff; 846 } 847 848 @Override 849 public final int getBlue(int pixel) { 850 return colorMap[pixel] & 0xff; 851 } 852 853 @Override 854 public final int getAlpha(int pixel) { 855 return (colorMap[pixel] >> 24) & 0xff; 856 } 857 858 @Override 859 public int[] getComponentSize() { 860 return bits.clone(); 861 } 862 863 /** 864 * Checks if this color model validates pixels. 865 * 866 * @return true, if all pixels are valid, otherwise false. 867 */ 868 public boolean isValid() { 869 return (validBits == null); 870 } 871 872 @Override 873 public void finalize() { 874 // TODO: implement 875 return; 876 } 877 878 /** 879 * Gets the index that represents the transparent pixel. 880 * 881 * @return the index that represents the transparent pixel. 882 */ 883 public final int getTransparentPixel() { 884 return transparentIndex; 885 } 886 887 @Override 888 public int getTransparency() { 889 return transparency; 890 } 891 892 /** 893 * Gets the size of the color map. 894 * 895 * @return the map size. 896 */ 897 public final int getMapSize() { 898 return mapSize; 899 } 900 901 /** 902 * Creates the color map. 903 * 904 * @param size 905 * the size. 906 * @param r 907 * the r. 908 * @param g 909 * the g. 910 * @param b 911 * the b. 912 * @param a 913 * the a. 914 * @param trans 915 * the trans. 916 */ 917 private void createColorMap(int size, byte r[], byte g[], byte b[], byte a[], int trans) { 918 if (size < 1) { 919 // awt.264=Size of the color map is less than 1 920 throw new IllegalArgumentException(Messages.getString("awt.264")); //$NON-NLS-1$ 921 } 922 923 mapSize = size; 924 colorMap = new int[mapSize]; 925 if (trans >= 0 && trans < mapSize) { 926 transparency = Transparency.BITMASK; 927 transparentIndex = trans; 928 } else { 929 transparency = Transparency.OPAQUE; 930 transparentIndex = -1; 931 } 932 int alpha = 0; 933 934 for (int i = 0; i < mapSize; i++) { 935 colorMap[i] = ((r[i] & 0xff) << 16) | ((g[i] & 0xff) << 8) | (b[i] & 0xff); 936 937 if (trans == i) { 938 continue; 939 } 940 941 if (a == null) { 942 colorMap[i] |= 0xff000000; 943 } else { 944 alpha = a[i] & 0xff; 945 if (alpha == 0xff) { 946 colorMap[i] |= 0xff000000; 947 } else if (alpha == 0) { 948 if (transparency == Transparency.OPAQUE) { 949 transparency = Transparency.BITMASK; 950 } 951 if (transparentIndex < 0) { 952 transparentIndex = i; 953 } 954 } else { 955 colorMap[i] |= (a[i] & 0xff) << 24; 956 if (transparency != Transparency.TRANSLUCENT) { 957 transparency = Transparency.TRANSLUCENT; 958 } 959 } 960 } 961 962 } 963 964 } 965 966 /** 967 * This method checking, if Color Map has Gray palette. 968 */ 969 private void checkPalette() { 970 grayPalette = false; 971 if (transparency > Transparency.OPAQUE) { 972 return; 973 } 974 int rgb = 0; 975 976 for (int i = 0; i < mapSize; i++) { 977 rgb = colorMap[i]; 978 if (((rgb >> 16) & 0xff) != ((rgb >> 8) & 0xff) || ((rgb >> 8) & 0xff) != (rgb & 0xff)) { 979 return; 980 } 981 } 982 grayPalette = true; 983 } 984 985 /** 986 * Construction an array pixel representation. 987 * 988 * @param colorMapIdx 989 * the index into Color Map. 990 * @param pixel 991 * the pixel 992 * @return the pixel representation array. 993 */ 994 private Object createDataObject(int colorMapIdx, Object pixel) { 995 if (pixel == null) { 996 switch (transferType) { 997 case DataBuffer.TYPE_BYTE: 998 byte[] ba = new byte[1]; 999 ba[0] = (byte)colorMapIdx; 1000 pixel = ba; 1001 break; 1002 case DataBuffer.TYPE_USHORT: 1003 short[] sa = new short[1]; 1004 sa[0] = (short)colorMapIdx; 1005 pixel = sa; 1006 break; 1007 default: 1008 // awt.267=The transferType is invalid 1009 throw new UnsupportedOperationException(Messages.getString("awt.267")); //$NON-NLS-1$ 1010 } 1011 } else if (pixel instanceof byte[] && transferType == DataBuffer.TYPE_BYTE) { 1012 byte ba[] = (byte[])pixel; 1013 ba[0] = (byte)colorMapIdx; 1014 pixel = ba; 1015 } else if (pixel instanceof short[] && transferType == DataBuffer.TYPE_USHORT) { 1016 short[] sa = (short[])pixel; 1017 sa[0] = (short)colorMapIdx; 1018 pixel = sa; 1019 } else if (pixel instanceof int[]) { 1020 int ia[] = (int[])pixel; 1021 ia[0] = colorMapIdx; 1022 pixel = ia; 1023 } else { 1024 // awt.268=The pixel is not a primitive array of type transferType 1025 throw new ClassCastException(Messages.getString("awt.268")); //$NON-NLS-1$ 1026 } 1027 return pixel; 1028 } 1029 1030 /** 1031 * Creates the bits. 1032 * 1033 * @param hasAlpha 1034 * the has alpha. 1035 * @return the int[]. 1036 */ 1037 private static int[] createBits(boolean hasAlpha) { 1038 1039 int numChannels; 1040 if (hasAlpha) { 1041 numChannels = 4; 1042 } else { 1043 numChannels = 3; 1044 } 1045 1046 int bits[] = new int[numChannels]; 1047 for (int i = 0; i < numChannels; i++) { 1048 bits[i] = 8; 1049 } 1050 1051 return bits; 1052 1053 } 1054 1055 /** 1056 * Validate transfer type. 1057 * 1058 * @param transferType 1059 * the transfer type. 1060 * @return the int. 1061 */ 1062 private static int validateTransferType(int transferType) { 1063 if (transferType != DataBuffer.TYPE_BYTE && transferType != DataBuffer.TYPE_USHORT) { 1064 // awt.269=The transferType is not one of DataBuffer.TYPE_BYTE or 1065 // DataBuffer.TYPE_USHORT 1066 throw new IllegalArgumentException(Messages.getString("awt.269")); //$NON-NLS-1$ 1067 } 1068 return transferType; 1069 } 1070 1071 /** 1072 * Checks if is gray palette. 1073 * 1074 * @return true, if is gray palette. 1075 */ 1076 boolean isGrayPallete() { 1077 return grayPalette; 1078 } 1079 1080 } 1081