1 7 8 package java.awt.image; 9 10 import java.awt.Transparency ; 11 import java.awt.color.ColorSpace ; 12 import java.math.BigInteger ; 13 14 98 public class IndexColorModel extends ColorModel { 99 private int rgb[]; 100 private int map_size; 101 private int transparent_index = -1; 102 private boolean allgrayopaque; 103 private BigInteger validBits; 104 105 private static int[] opaqueBits = {8, 8, 8}; 106 private static int[] alphaBits = {8, 8, 8, 8}; 107 108 static private native void initIDs(); 109 static { 110 ColorModel.loadLibraries(); 111 initIDs(); 112 } 113 136 public IndexColorModel(int bits, int size, 137 byte r[], byte g[], byte b[]) { 138 super(bits, opaqueBits, 139 ColorSpace.getInstance(ColorSpace.CS_sRGB), 140 false, false, OPAQUE, 141 ColorModel.getDefaultTransferType(bits)); 142 if (bits < 1 || bits > 16) { 143 throw new IllegalArgumentException ("Number of bits must be between" 144 +" 1 and 16."); 145 } 146 setRGBs(size, r, g, b, null); 147 } 148 149 175 public IndexColorModel(int bits, int size, 176 byte r[], byte g[], byte b[], int trans) { 177 super(bits, opaqueBits, 178 ColorSpace.getInstance(ColorSpace.CS_sRGB), 179 false, false, OPAQUE, 180 ColorModel.getDefaultTransferType(bits)); 181 if (bits < 1 || bits > 16) { 182 throw new IllegalArgumentException ("Number of bits must be between" 183 +" 1 and 16."); 184 } 185 setRGBs(size, r, g, b, null); 186 setTransparentPixel(trans); 187 } 188 189 213 public IndexColorModel(int bits, int size, 214 byte r[], byte g[], byte b[], byte a[]) { 215 super (bits, alphaBits, 216 ColorSpace.getInstance(ColorSpace.CS_sRGB), 217 true, false, TRANSLUCENT, 218 ColorModel.getDefaultTransferType(bits)); 219 if (bits < 1 || bits > 16) { 220 throw new IllegalArgumentException ("Number of bits must be between" 221 +" 1 and 16."); 222 } 223 setRGBs (size, r, g, b, a); 224 } 225 226 252 public IndexColorModel(int bits, int size, byte cmap[], int start, 253 boolean hasalpha) { 254 this(bits, size, cmap, start, hasalpha, -1); 255 if (bits < 1 || bits > 16) { 256 throw new IllegalArgumentException ("Number of bits must be between" 257 +" 1 and 16."); 258 } 259 } 260 261 289 public IndexColorModel(int bits, int size, byte cmap[], int start, 290 boolean hasalpha, int trans) { 291 super(bits, opaqueBits, 293 ColorSpace.getInstance(ColorSpace.CS_sRGB), 294 false, false, OPAQUE, 295 ColorModel.getDefaultTransferType(bits)); 296 297 if (bits < 1 || bits > 16) { 298 throw new IllegalArgumentException ("Number of bits must be between" 299 +" 1 and 16."); 300 } 301 if (size < 1) { 302 throw new IllegalArgumentException ("Map size ("+size+ 303 ") must be >= 1"); 304 } 305 map_size = size; 306 rgb = new int[calcRealMapSize(bits, size)]; 307 int j = start; 308 int alpha = 0xff; 309 boolean allgray = true; 310 int transparency = OPAQUE; 311 for (int i = 0; i < size; i++) { 312 int r = cmap[j++] & 0xff; 313 int g = cmap[j++] & 0xff; 314 int b = cmap[j++] & 0xff; 315 allgray = allgray && (r == g) && (g == b); 316 if (hasalpha) { 317 alpha = cmap[j++] & 0xff; 318 if (alpha != 0xff) { 319 if (alpha == 0x00) { 320 if (transparency == OPAQUE) { 321 transparency = BITMASK; 322 } 323 if (transparent_index < 0) { 324 transparent_index = i; 325 } 326 } else { 327 transparency = TRANSLUCENT; 328 } 329 allgray = false; 330 } 331 } 332 rgb[i] = (alpha << 24) | (r << 16) | (g << 8) | b; 333 } 334 this.allgrayopaque = allgray; 335 setTransparency(transparency); 336 setTransparentPixel(trans); 337 } 338 339 372 public IndexColorModel(int bits, int size, 373 int cmap[], int start, 374 boolean hasalpha, int trans, int transferType) { 375 super(bits, opaqueBits, 377 ColorSpace.getInstance(ColorSpace.CS_sRGB), 378 false, false, OPAQUE, 379 transferType); 380 381 if (bits < 1 || bits > 16) { 382 throw new IllegalArgumentException ("Number of bits must be between" 383 +" 1 and 16."); 384 } 385 if (size < 1) { 386 throw new IllegalArgumentException ("Map size ("+size+ 387 ") must be >= 1"); 388 } 389 if ((transferType != DataBuffer.TYPE_BYTE) && 390 (transferType != DataBuffer.TYPE_USHORT)) { 391 throw new IllegalArgumentException ("transferType must be either" + 392 "DataBuffer.TYPE_BYTE or DataBuffer.TYPE_USHORT"); 393 } 394 395 setRGBs(size, cmap, start, hasalpha); 396 setTransparentPixel(trans); 397 } 398 399 437 public IndexColorModel(int bits, int size, int cmap[], int start, 438 int transferType, BigInteger validBits) { 439 super (bits, alphaBits, 440 ColorSpace.getInstance(ColorSpace.CS_sRGB), 441 true, false, TRANSLUCENT, 442 transferType); 443 444 if (bits < 1 || bits > 16) { 445 throw new IllegalArgumentException ("Number of bits must be between" 446 +" 1 and 16."); 447 } 448 if (size < 1) { 449 throw new IllegalArgumentException ("Map size ("+size+ 450 ") must be >= 1"); 451 } 452 if ((transferType != DataBuffer.TYPE_BYTE) && 453 (transferType != DataBuffer.TYPE_USHORT)) { 454 throw new IllegalArgumentException ("transferType must be either" + 455 "DataBuffer.TYPE_BYTE or DataBuffer.TYPE_USHORT"); 456 } 457 458 if (validBits != null) { 459 for (int i=0; i < size; i++) { 461 if (!validBits.testBit(i)) { 462 this.validBits = validBits; 463 break; 464 } 465 } 466 } 467 468 setRGBs(size, cmap, start, true); 469 } 470 471 private void setRGBs(int size, byte r[], byte g[], byte b[], byte a[]) { 472 if (size < 1) { 473 throw new IllegalArgumentException ("Map size ("+size+ 474 ") must be >= 1"); 475 } 476 map_size = size; 477 rgb = new int[calcRealMapSize(pixel_bits, size)]; 478 int alpha = 0xff; 479 int transparency = OPAQUE; 480 boolean allgray = true; 481 for (int i = 0; i < size; i++) { 482 int rc = r[i] & 0xff; 483 int gc = g[i] & 0xff; 484 int bc = b[i] & 0xff; 485 allgray = allgray && (rc == gc) && (gc == bc); 486 if (a != null) { 487 alpha = a[i] & 0xff; 488 if (alpha != 0xff) { 489 if (alpha == 0x00) { 490 if (transparency == OPAQUE) { 491 transparency = BITMASK; 492 } 493 if (transparent_index < 0) { 494 transparent_index = i; 495 } 496 } else { 497 transparency = TRANSLUCENT; 498 } 499 allgray = false; 500 } 501 } 502 rgb[i] = (alpha << 24) | (rc << 16) | (gc << 8) | bc; 503 } 504 this.allgrayopaque = allgray; 505 setTransparency(transparency); 506 } 507 508 private void setRGBs(int size, int cmap[], int start, boolean hasalpha) { 509 map_size = size; 510 rgb = new int[calcRealMapSize(pixel_bits, size)]; 511 int j = start; 512 int transparency = OPAQUE; 513 boolean allgray = true; 514 BigInteger validBits = this.validBits; 515 for (int i = 0; i < size; i++, j++) { 516 if (validBits != null && !validBits.testBit(i)) { 517 continue; 518 } 519 int cmaprgb = cmap[j]; 520 int r = (cmaprgb >> 16) & 0xff; 521 int g = (cmaprgb >> 8) & 0xff; 522 int b = (cmaprgb ) & 0xff; 523 allgray = allgray && (r == g) && (g == b); 524 if (hasalpha) { 525 int alpha = cmaprgb >>> 24; 526 if (alpha != 0xff) { 527 if (alpha == 0x00) { 528 if (transparency == OPAQUE) { 529 transparency = BITMASK; 530 } 531 if (transparent_index < 0) { 532 transparent_index = i; 533 } 534 } else { 535 transparency = TRANSLUCENT; 536 } 537 allgray = false; 538 } 539 } else { 540 cmaprgb |= 0xff000000; 541 } 542 rgb[i] = cmaprgb; 543 } 544 this.allgrayopaque = allgray; 545 setTransparency(transparency); 546 } 547 548 private int calcRealMapSize(int bits, int size) { 549 int newSize = Math.max(1 << bits, size); 550 return Math.max(newSize, 256); 551 } 552 553 private BigInteger getAllValid() { 554 int numbytes = (map_size+7)/8; 555 byte[] valid = new byte[numbytes]; 556 java.util.Arrays.fill(valid, (byte)0xff); 557 valid[0] = (byte)(0xff >>> (numbytes*8 - map_size)); 558 559 return new BigInteger (1, valid); 560 } 561 562 570 public int getTransparency() { 571 return transparency; 572 } 573 574 581 public int[] getComponentSize() { 582 if (nBits == null) { 583 if (supportsAlpha) { 584 nBits = new int[4]; 585 nBits[3] = 8; 586 } 587 else { 588 nBits = new int[3]; 589 } 590 nBits[0] = nBits[1] = nBits[2] = 8; 591 } 592 return nBits; 593 } 594 595 600 final public int getMapSize() { 601 return map_size; 602 } 603 604 616 final public int getTransparentPixel() { 617 return transparent_index; 618 } 619 620 627 final public void getReds(byte r[]) { 628 for (int i = 0; i < map_size; i++) { 629 r[i] = (byte) (rgb[i] >> 16); 630 } 631 } 632 633 640 final public void getGreens(byte g[]) { 641 for (int i = 0; i < map_size; i++) { 642 g[i] = (byte) (rgb[i] >> 8); 643 } 644 } 645 646 653 final public void getBlues(byte b[]) { 654 for (int i = 0; i < map_size; i++) { 655 b[i] = (byte) rgb[i]; 656 } 657 } 658 659 666 final public void getAlphas(byte a[]) { 667 for (int i = 0; i < map_size; i++) { 668 a[i] = (byte) (rgb[i] >> 24); 669 } 670 } 671 672 683 final public void getRGBs(int rgb[]) { 684 System.arraycopy(this.rgb, 0, rgb, 0, map_size); 685 } 686 687 private void setTransparentPixel(int trans) { 688 if (trans >= 0 && trans < map_size) { 689 rgb[trans] &= 0x00ffffff; 690 transparent_index = trans; 691 allgrayopaque = false; 692 if (this.transparency == OPAQUE) { 693 setTransparency(BITMASK); 694 } 695 } 696 } 697 698 private void setTransparency(int transparency) { 699 if (this.transparency != transparency) { 700 this.transparency = transparency; 701 if (transparency == OPAQUE) { 702 supportsAlpha = false; 703 numComponents = 3; 704 nBits = opaqueBits; 705 } else { 706 supportsAlpha = true; 707 numComponents = 4; 708 nBits = alphaBits; 709 } 710 } 711 } 712 713 721 final public int getRed(int pixel) { 722 return (rgb[pixel] >> 16) & 0xff; 723 } 724 725 733 final public int getGreen(int pixel) { 734 return (rgb[pixel] >> 8) & 0xff; 735 } 736 737 745 final public int getBlue(int pixel) { 746 return rgb[pixel] & 0xff; 747 } 748 749 755 final public int getAlpha(int pixel) { 756 return (rgb[pixel] >> 24) & 0xff; 757 } 758 759 767 final public int getRGB(int pixel) { 768 return rgb[pixel]; 769 } 770 771 private static final int CACHESIZE = 40; 772 private int lookupcache[] = new int[CACHESIZE]; 773 774 808 public synchronized Object getDataElements(int rgb, Object pixel) { 809 int red = (rgb>>16) & 0xff; 810 int green = (rgb>>8) & 0xff; 811 int blue = rgb & 0xff; 812 int alpha = (rgb>>>24); 813 int pix = 0; 814 815 for (int i = CACHESIZE - 2; i >= 0; i -= 2) { 816 if ((pix = lookupcache[i]) == 0) { 817 break; 818 } 819 if (rgb == lookupcache[i+1]) { 820 return installpixel(pixel, ~pix); 821 } 822 } 823 824 if (allgrayopaque) { 825 int minDist = 256; 826 int d; 827 int gray = (int) (red*77 + green*150 + blue*29 + 128)/256; 828 829 for (int i = 0; i < map_size; i++) { 830 if (this.rgb[i] == 0x0) { 831 continue; 835 } 836 d = (this.rgb[i] & 0xff) - gray; 837 if (d < 0) d = -d; 838 if (d < minDist) { 839 pix = i; 840 if (d == 0) { 841 break; 842 } 843 minDist = d; 844 } 845 } 846 } else if (alpha == 0) { 847 if (transparent_index >= 0) { 849 pix = transparent_index; 850 } 851 else { 852 int smallestAlpha = 256; 854 for (int i = 0; i < map_size; i++) { 855 int a = this.rgb[i] >>> 24; 856 if (smallestAlpha > alpha && 857 (validBits == null || validBits.testBit(i))) 858 { 859 smallestAlpha = alpha; 860 pix = i; 861 } 862 } 863 } 864 } else { 865 int smallestError = 255 * 255 * 255; int smallestAlphaError = 255; 873 874 if (false && red == green && green == blue) { 875 } 877 878 for (int i=0; i < map_size; i++) { 879 int lutrgb = this.rgb[i]; 880 if (lutrgb == rgb) { 881 pix = i; 882 break; 883 } 884 int tmp = (lutrgb>>>24) - alpha; 885 if (tmp < 0) { 886 tmp = -tmp; 887 } 888 if (tmp <= smallestAlphaError) { 889 smallestAlphaError = tmp; 890 tmp = ((lutrgb>>16) & 0xff) - red; 891 int currentError = tmp * tmp; 892 if (currentError < smallestError) { 893 tmp = ((lutrgb>>8) & 0xff) - green; 894 currentError += tmp * tmp; 895 if (currentError < smallestError) { 896 tmp = (lutrgb & 0xff) - blue; 897 currentError += tmp * tmp; 898 if (currentError < smallestError && 899 (validBits == null || validBits.testBit(i))) 900 { 901 pix = i; 902 smallestError = currentError; 903 } 904 } 905 } 906 } 907 } 908 } 909 System.arraycopy(lookupcache, 2, lookupcache, 0, CACHESIZE - 2); 910 lookupcache[CACHESIZE - 1] = rgb; 911 lookupcache[CACHESIZE - 2] = ~pix; 912 return installpixel(pixel, pix); 913 } 914 915 private Object installpixel(Object pixel, int pix) { 916 switch (transferType) { 917 case DataBuffer.TYPE_INT: 918 int[] intObj; 919 if (pixel == null) { 920 pixel = intObj = new int[1]; 921 } else { 922 intObj = (int[]) pixel; 923 } 924 intObj[0] = pix; 925 break; 926 case DataBuffer.TYPE_BYTE: 927 byte[] byteObj; 928 if (pixel == null) { 929 pixel = byteObj = new byte[1]; 930 } else { 931 byteObj = (byte[]) pixel; 932 } 933 byteObj[0] = (byte) pix; 934 break; 935 case DataBuffer.TYPE_USHORT: 936 short[] shortObj; 937 if (pixel == null) { 938 pixel = shortObj = new short[1]; 939 } else { 940 shortObj = (short[]) pixel; 941 } 942 shortObj[0] = (short) pix; 943 break; 944 default: 945 throw new UnsupportedOperationException ("This method has not been "+ 946 "implemented for transferType " + transferType); 947 } 948 return pixel; 949 } 950 951 976 public int[] getComponents(int pixel, int[] components, int offset) { 977 if (components == null) { 978 components = new int[offset+numComponents]; 979 } 980 981 components[offset+0] = getRed(pixel); 983 components[offset+1] = getGreen(pixel); 984 components[offset+2] = getBlue(pixel); 985 if (supportsAlpha && (components.length-offset) > 3) { 986 components[offset+3] = getAlpha(pixel); 987 } 988 989 return components; 990 } 991 992 1042 public int[] getComponents(Object pixel, int[] components, int offset) { 1043 int intpixel; 1044 switch (transferType) { 1045 case DataBuffer.TYPE_BYTE: 1046 byte bdata[] = (byte[])pixel; 1047 intpixel = bdata[0] & 0xff; 1048 break; 1049 case DataBuffer.TYPE_USHORT: 1050 short sdata[] = (short[])pixel; 1051 intpixel = sdata[0] & 0xffff; 1052 break; 1053 case DataBuffer.TYPE_INT: 1054 int idata[] = (int[])pixel; 1055 intpixel = idata[0]; 1056 break; 1057 default: 1058 throw new UnsupportedOperationException ("This method has not been "+ 1059 "implemented for transferType " + transferType); 1060 } 1061 return getComponents(intpixel, components, offset); 1062 } 1063 1064 1088 public int getDataElement(int[] components, int offset) { 1089 int rgb = (components[offset+0]<<16) 1090 | (components[offset+1]<<8) | (components[offset+2]); 1091 if (supportsAlpha) { 1092 rgb |= (components[offset+3]<<24); 1093 } 1094 else { 1095 rgb |= 0xff000000; 1096 } 1097 Object inData = getDataElements(rgb, null); 1098 int pixel; 1099 switch (transferType) { 1100 case DataBuffer.TYPE_BYTE: 1101 byte bdata[] = (byte[])inData; 1102 pixel = bdata[0] & 0xff; 1103 break; 1104 case DataBuffer.TYPE_USHORT: 1105 short sdata[] = (short[])inData; 1106 pixel = sdata[0]; 1107 break; 1108 case DataBuffer.TYPE_INT: 1109 int idata[] = (int[])inData; 1110 pixel = idata[0]; 1111 break; 1112 default: 1113 throw new UnsupportedOperationException ("This method has not been "+ 1114 "implemented for transferType " + transferType); 1115 } 1116 return pixel; 1117 } 1118 1119 1161 public Object getDataElements(int[] components, int offset, Object pixel) { 1162 int rgb = (components[offset+0]<<16) | (components[offset+1]<<8) 1163 | (components[offset+2]); 1164 if (supportsAlpha) { 1165 rgb |= (components[offset+3]<<24); 1166 } 1167 else { 1168 rgb &= 0xff000000; 1169 } 1170 return getDataElements(rgb, pixel); 1171 } 1172 1173 1192 public WritableRaster createCompatibleWritableRaster(int w, int h) { 1193 WritableRaster raster; 1194 1195 if (pixel_bits == 1 || pixel_bits == 2 || pixel_bits == 4) { 1196 raster = Raster.createPackedRaster(DataBuffer.TYPE_BYTE, 1198 w, h, 1, pixel_bits, null); 1199 } 1200 else if (pixel_bits <= 8) { 1201 raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, 1202 w,h,1,null); 1203 } 1204 else if (pixel_bits <= 16) { 1205 raster = Raster.createInterleavedRaster(DataBuffer.TYPE_USHORT, 1206 w,h,1,null); 1207 } 1208 else { 1209 throw new 1210 UnsupportedOperationException ("This method is not supported "+ 1211 " for pixel bits > 16."); 1212 } 1213 return raster; 1214 } 1215 1216 1225 public boolean isCompatibleRaster(Raster raster) { 1226 1227 int size = raster.getSampleModel().getSampleSize(0); 1228 return ((raster.getTransferType() == transferType) && 1229 (raster.getNumBands() == 1) && ((1 << size) >= map_size)); 1230 } 1231 1232 1244 public SampleModel createCompatibleSampleModel(int w, int h) { 1245 int[] off = new int[1]; 1246 off[0] = 0; 1247 if (pixel_bits == 1 || pixel_bits == 2 || pixel_bits == 4) { 1248 return new MultiPixelPackedSampleModel (transferType, w, h, 1249 pixel_bits); 1250 } 1251 else { 1252 return new ComponentSampleModel (transferType, w, h, 1, w, 1253 off); 1254 } 1255 } 1256 1257 1268 public boolean isCompatibleSampleModel(SampleModel sm) { 1269 if (! (sm instanceof ComponentSampleModel ) && 1271 ! (sm instanceof MultiPixelPackedSampleModel ) ) { 1272 return false; 1273 } 1274 1275 if (sm.getTransferType() != transferType) { 1277 return false; 1278 } 1279 1280 if (sm.getNumBands() != 1) { 1281 return false; 1282 } 1283 1284 return true; 1285 } 1286 1287 1304 public BufferedImage convertToIntDiscrete(Raster raster, 1305 boolean forceARGB) { 1306 ColorModel cm; 1307 1308 if (!isCompatibleRaster(raster)) { 1309 throw new IllegalArgumentException ("This raster is not compatible" + 1310 "with this IndexColorModel."); 1311 } 1312 if (forceARGB || transparency == TRANSLUCENT) { 1313 cm = ColorModel.getRGBdefault(); 1314 } 1315 else if (transparency == BITMASK) { 1316 cm = new DirectColorModel (25, 0xff0000, 0x00ff00, 0x0000ff, 1317 0x1000000); 1318 } 1319 else { 1320 cm = new DirectColorModel (24, 0xff0000, 0x00ff00, 0x0000ff); 1321 } 1322 1323 int w = raster.getWidth(); 1324 int h = raster.getHeight(); 1325 WritableRaster discreteRaster = 1326 cm.createCompatibleWritableRaster(w, h); 1327 Object obj = null; 1328 int[] data = null; 1329 1330 int rX = raster.getMinX(); 1331 int rY = raster.getMinY(); 1332 1333 for (int y=0; y < h; y++, rY++) { 1334 obj = raster.getDataElements(rX, rY, w, 1, obj); 1335 if (obj instanceof int[]) { 1336 data = (int[])obj; 1337 } else { 1338 data = DataBuffer.toIntArray(obj); 1339 } 1340 for (int x=0; x < w; x++) { 1341 data[x] = rgb[data[x]]; 1342 } 1343 discreteRaster.setDataElements(0, y, w, 1, data); 1344 } 1345 1346 return new BufferedImage (cm, discreteRaster, false, null); 1347 } 1348 1349 1355 public boolean isValid(int pixel) { 1356 return ((pixel >= 0 && pixel < map_size) && 1357 (validBits == null || validBits.testBit(pixel))); 1358 } 1359 1360 1365 public boolean isValid() { 1366 return (validBits == null); 1367 } 1368 1369 1378 public BigInteger getValidPixels() { 1379 if (validBits == null) { 1380 return getAllValid(); 1381 } 1382 else { 1383 return validBits; 1384 } 1385 } 1386 1387 1392 public void finalize() { 1393 sun.awt.image.BufImgSurfaceData.freeNativeICMData(this); 1394 } 1395 1396 1402 public String toString() { 1403 return new String ("IndexColorModel: #pixelBits = "+pixel_bits 1404 + " numComponents = "+numComponents 1405 + " color space = "+colorSpace 1406 + " transparency = "+transparency 1407 + " transIndex = "+transparent_index 1408 + " has alpha = "+supportsAlpha 1409 + " isAlphaPre = "+isAlphaPremultiplied 1410 ); 1411 } 1412} 1413 | Popular Tags |