1 /* 2 * Copyright (c) 1995, 2001, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package java.awt.image; 27 28 import java.awt.color.ColorSpace; 29 import java.awt.Transparency; 30 31 /** 32 * The <code>DirectColorModel</code> class is a <code>ColorModel</code> 33 * class that works with pixel values that represent RGB 34 * color and alpha information as separate samples and that pack all 35 * samples for a single pixel into a single int, short, or byte quantity. 36 * This class can be used only with ColorSpaces of type ColorSpace.TYPE_RGB. 37 * In addition, for each component of the ColorSpace, the minimum 38 * normalized component value obtained via the <code>getMinValue()</code> 39 * method of ColorSpace must be 0.0, and the maximum value obtained via 40 * the <code>getMaxValue()</code> method must be 1.0 (these min/max 41 * values are typical for RGB spaces). 42 * There must be three color samples in the pixel values and there can 43 * be a single alpha sample. For those methods that use a primitive array 44 * pixel representation of type <code>transferType</code>, the array 45 * length is always one. The transfer 46 * types supported are DataBuffer.TYPE_BYTE, 47 * DataBuffer.TYPE_USHORT, and DataBuffer.TYPE_INT. 48 * Color and alpha samples are stored in the single 49 * element of the array in bits indicated by bit masks. Each bit mask 50 * must be contiguous and masks must not overlap. The same masks apply to 51 * the single int pixel representation used by other methods. The 52 * correspondence of masks and color/alpha samples is as follows: 53 * <ul> 54 * <li> Masks are identified by indices running from 0 through 2 55 * if no alpha is present, or 3 if an alpha is present. 56 * <li> The first three indices refer to color samples; 57 * index 0 corresponds to red, index 1 to green, and index 2 to blue. 58 * <li> Index 3 corresponds to the alpha sample, if present. 59 * </ul> 60 * <p> 61 * The translation from pixel values to color/alpha components for 62 * display or processing purposes is a one-to-one correspondence of 63 * samples to components. A <code>DirectColorModel</code> is 64 * typically used with image data which uses masks to define packed 65 * samples. For example, a <code>DirectColorModel</code> can be used in 66 * conjunction with a <code>SinglePixelPackedSampleModel</code> to 67 * construct a {@link BufferedImage}. Normally the masks used by the 68 * {@link SampleModel} and the <code>ColorModel</code> would be the 69 * same. However, if they are different, the color interpretation 70 * of pixel data will be done according to the masks of the 71 * <code>ColorModel</code>. 72 * <p> 73 * A single int pixel representation is valid for all objects of this 74 * class, since it is always possible to represent pixel values used with 75 * this class in a single int. Therefore, methods which use this 76 * representation will not throw an <code>IllegalArgumentException</code> 77 * due to an invalid pixel value. 78 * <p> 79 * This color model is similar to an X11 TrueColor visual. 80 * The default RGB ColorModel specified by the 81 * {@link ColorModel#getRGBdefault() getRGBdefault} method is a 82 * <code>DirectColorModel</code> with the following parameters: 83 * <pre> 84 * Number of bits: 32 85 * Red mask: 0x00ff0000 86 * Green mask: 0x0000ff00 87 * Blue mask: 0x000000ff 88 * Alpha mask: 0xff000000 89 * Color space: sRGB 90 * isAlphaPremultiplied: False 91 * Transparency: Transparency.TRANSLUCENT 92 * transferType: DataBuffer.TYPE_INT 93 * </pre> 94 * <p> 95 * Many of the methods in this class are final. This is because the 96 * underlying native graphics code makes assumptions about the layout 97 * and operation of this class and those assumptions are reflected in 98 * the implementations of the methods here that are marked final. You 99 * can subclass this class for other reasons, but you cannot override 100 * or modify the behavior of those methods. 101 * 102 * @see ColorModel 103 * @see ColorSpace 104 * @see SinglePixelPackedSampleModel 105 * @see BufferedImage 106 * @see ColorModel#getRGBdefault 107 * 108 */ 109 public class DirectColorModel extends PackedColorModel { 110 private int red_mask; 111 private int green_mask; 112 private int blue_mask; 113 private int alpha_mask; 114 private int red_offset; 115 private int green_offset; 116 private int blue_offset; 117 private int alpha_offset; 118 private int red_scale; 119 private int green_scale; 120 private int blue_scale; 121 private int alpha_scale; 122 private boolean is_LinearRGB; 123 private int lRGBprecision; 124 private byte[] tosRGB8LUT; 125 private byte[] fromsRGB8LUT8; 126 private short[] fromsRGB8LUT16; 127 128 /** 129 * Constructs a <code>DirectColorModel</code> from the specified masks 130 * that indicate which bits in an <code>int</code> pixel representation 131 * contain the red, green and blue color samples. As pixel values do not 132 * contain alpha information, all pixels are treated as opaque, which 133 * means that alpha = 1.0. All of the bits 134 * in each mask must be contiguous and fit in the specified number 135 * of least significant bits of an <code>int</code> pixel representation. 136 * The <code>ColorSpace</code> is the default sRGB space. The 137 * transparency value is Transparency.OPAQUE. The transfer type 138 * is the smallest of DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT, 139 * or DataBuffer.TYPE_INT that can hold a single pixel. 140 * @param bits the number of bits in the pixel values; for example, 141 * the sum of the number of bits in the masks. 142 * @param rmask specifies a mask indicating which bits in an 143 * integer pixel contain the red component 144 * @param gmask specifies a mask indicating which bits in an 145 * integer pixel contain the green component 146 * @param bmask specifies a mask indicating which bits in an 147 * integer pixel contain the blue component 148 * 149 */ 150 public DirectColorModel(int bits, 151 int rmask, int gmask, int bmask) { 152 this(bits, rmask, gmask, bmask, 0); 153 } 154 155 /** 156 * Constructs a <code>DirectColorModel</code> from the specified masks 157 * that indicate which bits in an <code>int</code> pixel representation 158 * contain the red, green and blue color samples and the alpha sample, 159 * if present. If <code>amask</code> is 0, pixel values do not contain 160 * alpha information and all pixels are treated as opaque, which means 161 * that alpha = 1.0. All of the bits in each mask must 162 * be contiguous and fit in the specified number of least significant bits 163 * of an <code>int</code> pixel representation. Alpha, if present, is not 164 * premultiplied. The <code>ColorSpace</code> is the default sRGB space. 165 * The transparency value is Transparency.OPAQUE if no alpha is 166 * present, or Transparency.TRANSLUCENT otherwise. The transfer type 167 * is the smallest of DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT, 168 * or DataBuffer.TYPE_INT that can hold a single pixel. 169 * @param bits the number of bits in the pixel values; for example, 170 * the sum of the number of bits in the masks. 171 * @param rmask specifies a mask indicating which bits in an 172 * integer pixel contain the red component 173 * @param gmask specifies a mask indicating which bits in an 174 * integer pixel contain the green component 175 * @param bmask specifies a mask indicating which bits in an 176 * integer pixel contain the blue component 177 * @param amask specifies a mask indicating which bits in an 178 * integer pixel contain the alpha component 179 */ 180 public DirectColorModel(int bits, int rmask, int gmask, 181 int bmask, int amask) { 182 super (ColorSpace.getInstance(ColorSpace.CS_sRGB), 183 bits, rmask, gmask, bmask, amask, false, 184 amask == 0 ? Transparency.OPAQUE : Transparency.TRANSLUCENT, 185 ColorModel.getDefaultTransferType(bits)); 186 setFields(); 187 } 188 189 /** 190 * Constructs a <code>DirectColorModel</code> from the specified 191 * parameters. Color components are in the specified 192 * <code>ColorSpace</code>, which must be of type ColorSpace.TYPE_RGB 193 * and have minimum normalized component values which are all 0.0 194 * and maximum values which are all 1.0. 195 * The masks specify which bits in an <code>int</code> pixel 196 * representation contain the red, green and blue color samples and 197 * the alpha sample, if present. If <code>amask</code> is 0, pixel 198 * values do not contain alpha information and all pixels are treated 199 * as opaque, which means that alpha = 1.0. All of the 200 * bits in each mask must be contiguous and fit in the specified number 201 * of least significant bits of an <code>int</code> pixel 202 * representation. If there is alpha, the <code>boolean</code> 203 * <code>isAlphaPremultiplied</code> specifies how to interpret 204 * color and alpha samples in pixel values. If the <code>boolean</code> 205 * is <code>true</code>, color samples are assumed to have been 206 * multiplied by the alpha sample. The transparency value is 207 * Transparency.OPAQUE, if no alpha is present, or 208 * Transparency.TRANSLUCENT otherwise. The transfer type 209 * is the type of primitive array used to represent pixel values and 210 * must be one of DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT, or 211 * DataBuffer.TYPE_INT. 212 * @param space the specified <code>ColorSpace</code> 213 * @param bits the number of bits in the pixel values; for example, 214 * the sum of the number of bits in the masks. 215 * @param rmask specifies a mask indicating which bits in an 216 * integer pixel contain the red component 217 * @param gmask specifies a mask indicating which bits in an 218 * integer pixel contain the green component 219 * @param bmask specifies a mask indicating which bits in an 220 * integer pixel contain the blue component 221 * @param amask specifies a mask indicating which bits in an 222 * integer pixel contain the alpha component 223 * @param isAlphaPremultiplied <code>true</code> if color samples are 224 * premultiplied by the alpha sample; <code>false</code> otherwise 225 * @param transferType the type of array used to represent pixel values 226 * @throws IllegalArgumentException if <code>space</code> is not a 227 * TYPE_RGB space or if the min/max normalized component 228 * values are not 0.0/1.0. 229 */ 230 public DirectColorModel(ColorSpace space, int bits, int rmask, 231 int gmask, int bmask, int amask, 232 boolean isAlphaPremultiplied, 233 int transferType) { 234 super (space, bits, rmask, gmask, bmask, amask, 235 isAlphaPremultiplied, 236 amask == 0 ? Transparency.OPAQUE : Transparency.TRANSLUCENT, 237 transferType); 238 if (ColorModel.isLinearRGBspace(colorSpace)) { 239 is_LinearRGB = true; 240 if (maxBits <= 8) { 241 lRGBprecision = 8; 242 tosRGB8LUT = ColorModel.getLinearRGB8TosRGB8LUT(); 243 fromsRGB8LUT8 = ColorModel.getsRGB8ToLinearRGB8LUT(); 244 } else { 245 lRGBprecision = 16; 246 tosRGB8LUT = ColorModel.getLinearRGB16TosRGB8LUT(); 247 fromsRGB8LUT16 = ColorModel.getsRGB8ToLinearRGB16LUT(); 248 } 249 } else if (!is_sRGB) { 250 for (int i = 0; i < 3; i++) { 251 // super constructor checks that space is TYPE_RGB 252 // check here that min/max are all 0.0/1.0 253 if ((space.getMinValue(i) != 0.0f) || 254 (space.getMaxValue(i) != 1.0f)) { 255 throw new IllegalArgumentException( 256 "Illegal min/max RGB component value"); 257 } 258 } 259 } 260 setFields(); 261 } 262 263 /** 264 * Returns the mask indicating which bits in an <code>int</code> pixel 265 * representation contain the red color component. 266 * @return the mask, which indicates which bits of the <code>int</code> 267 * pixel representation contain the red color sample. 268 */ 269 final public int getRedMask() { 270 return maskArray[0]; 271 } 272 273 /** 274 * Returns the mask indicating which bits in an <code>int</code> pixel 275 * representation contain the green color component. 276 * @return the mask, which indicates which bits of the <code>int</code> 277 * pixel representation contain the green color sample. 278 */ 279 final public int getGreenMask() { 280 return maskArray[1]; 281 } 282 283 /** 284 * Returns the mask indicating which bits in an <code>int</code> pixel 285 * representation contain the blue color component. 286 * @return the mask, which indicates which bits of the <code>int</code> 287 * pixel representation contain the blue color sample. 288 */ 289 final public int getBlueMask() { 290 return maskArray[2]; 291 } 292 293 /** 294 * Returns the mask indicating which bits in an <code>int</code> pixel 295 * representation contain the alpha component. 296 * @return the mask, which indicates which bits of the <code>int</code> 297 * pixel representation contain the alpha sample. 298 */ 299 final public int getAlphaMask() { 300 if (supportsAlpha) { 301 return maskArray[3]; 302 } else { 303 return 0; 304 } 305 } 306 307 308 /* 309 * Given an int pixel in this ColorModel's ColorSpace, converts 310 * it to the default sRGB ColorSpace and returns the R, G, and B 311 * components as float values between 0.0 and 1.0. 312 */ 313 private float[] getDefaultRGBComponents(int pixel) { 314 int components[] = getComponents(pixel, null, 0); 315 float norm[] = getNormalizedComponents(components, 0, null, 0); 316 // Note that getNormalizedComponents returns non-premultiplied values 317 return colorSpace.toRGB(norm); 318 } 319 320 321 private int getsRGBComponentFromsRGB(int pixel, int idx) { 322 int c = ((pixel & maskArray[idx]) >>> maskOffsets[idx]); 323 if (isAlphaPremultiplied) { 324 int a = ((pixel & maskArray[3]) >>> maskOffsets[3]); 325 c = (a == 0) ? 0 : 326 (int) (((c * scaleFactors[idx]) * 255.0f / 327 (a * scaleFactors[3])) + 0.5f); 328 } else if (scaleFactors[idx] != 1.0f) { 329 c = (int) ((c * scaleFactors[idx]) + 0.5f); 330 } 331 return c; 332 } 333 334 335 private int getsRGBComponentFromLinearRGB(int pixel, int idx) { 336 int c = ((pixel & maskArray[idx]) >>> maskOffsets[idx]); 337 if (isAlphaPremultiplied) { 338 float factor = (float) ((1 << lRGBprecision) - 1); 339 int a = ((pixel & maskArray[3]) >>> maskOffsets[3]); 340 c = (a == 0) ? 0 : 341 (int) (((c * scaleFactors[idx]) * factor / 342 (a * scaleFactors[3])) + 0.5f); 343 } else if (nBits[idx] != lRGBprecision) { 344 if (lRGBprecision == 16) { 345 c = (int) ((c * scaleFactors[idx] * 257.0f) + 0.5f); 346 } else { 347 c = (int) ((c * scaleFactors[idx]) + 0.5f); 348 } 349 } 350 // now range of c is 0-255 or 0-65535, depending on lRGBprecision 351 return tosRGB8LUT[c] & 0xff; 352 } 353 354 355 /** 356 * Returns the red color component for the specified pixel, scaled 357 * from 0 to 255 in the default RGB <code>ColorSpace</code>, sRGB. A 358 * color conversion is done if necessary. The pixel value is specified 359 * as an <code>int</code>. 360 * The returned value is a non pre-multiplied value. Thus, if the 361 * alpha is premultiplied, this method divides it out before returning 362 * the value. If the alpha value is 0, for example, the red value 363 * is 0. 364 * @param pixel the specified pixel 365 * @return the red color component for the specified pixel, from 366 * 0 to 255 in the sRGB <code>ColorSpace</code>. 367 */ 368 final public int getRed(int pixel) { 369 if (is_sRGB) { 370 return getsRGBComponentFromsRGB(pixel, 0); 371 } else if (is_LinearRGB) { 372 return getsRGBComponentFromLinearRGB(pixel, 0); 373 } 374 float rgb[] = getDefaultRGBComponents(pixel); 375 return (int) (rgb[0] * 255.0f + 0.5f); 376 } 377 378 /** 379 * Returns the green color component for the specified pixel, scaled 380 * from 0 to 255 in the default RGB <code>ColorSpace</code>, sRGB. A 381 * color conversion is done if necessary. The pixel value is specified 382 * as an <code>int</code>. 383 * The returned value is a non pre-multiplied value. Thus, if the 384 * alpha is premultiplied, this method divides it out before returning 385 * the value. If the alpha value is 0, for example, the green value 386 * is 0. 387 * @param pixel the specified pixel 388 * @return the green color component for the specified pixel, from 389 * 0 to 255 in the sRGB <code>ColorSpace</code>. 390 */ 391 final public int getGreen(int pixel) { 392 if (is_sRGB) { 393 return getsRGBComponentFromsRGB(pixel, 1); 394 } else if (is_LinearRGB) { 395 return getsRGBComponentFromLinearRGB(pixel, 1); 396 } 397 float rgb[] = getDefaultRGBComponents(pixel); 398 return (int) (rgb[1] * 255.0f + 0.5f); 399 } 400 401 /** 402 * Returns the blue color component for the specified pixel, scaled 403 * from 0 to 255 in the default RGB <code>ColorSpace</code>, sRGB. A 404 * color conversion is done if necessary. The pixel value is specified 405 * as an <code>int</code>. 406 * The returned value is a non pre-multiplied value. Thus, if the 407 * alpha is premultiplied, this method divides it out before returning 408 * the value. If the alpha value is 0, for example, the blue value 409 * is 0. 410 * @param pixel the specified pixel 411 * @return the blue color component for the specified pixel, from 412 * 0 to 255 in the sRGB <code>ColorSpace</code>. 413 */ 414 final public int getBlue(int pixel) { 415 if (is_sRGB) { 416 return getsRGBComponentFromsRGB(pixel, 2); 417 } else if (is_LinearRGB) { 418 return getsRGBComponentFromLinearRGB(pixel, 2); 419 } 420 float rgb[] = getDefaultRGBComponents(pixel); 421 return (int) (rgb[2] * 255.0f + 0.5f); 422 } 423 424 /** 425 * Returns the alpha component for the specified pixel, scaled 426 * from 0 to 255. The pixel value is specified as an <code>int</code>. 427 * @param pixel the specified pixel 428 * @return the value of the alpha component of <code>pixel</code> 429 * from 0 to 255. 430 */ 431 final public int getAlpha(int pixel) { 432 if (!supportsAlpha) return 255; 433 int a = ((pixel & maskArray[3]) >>> maskOffsets[3]); 434 if (scaleFactors[3] != 1.0f) { 435 a = (int)(a * scaleFactors[3] + 0.5f); 436 } 437 return a; 438 } 439 440 /** 441 * Returns the color/alpha components of the pixel in the default 442 * RGB color model format. A color conversion is done if necessary. 443 * The pixel value is specified as an <code>int</code>. 444 * The returned value is in a non pre-multiplied format. Thus, if 445 * the alpha is premultiplied, this method divides it out of the 446 * color components. If the alpha value is 0, for example, the color 447 * values are each 0. 448 * @param pixel the specified pixel 449 * @return the RGB value of the color/alpha components of the specified 450 * pixel. 451 * @see ColorModel#getRGBdefault 452 */ 453 final public int getRGB(int pixel) { 454 if (is_sRGB || is_LinearRGB) { 455 return (getAlpha(pixel) << 24) 456 | (getRed(pixel) << 16) 457 | (getGreen(pixel) << 8) 458 | (getBlue(pixel) << 0); 459 } 460 float rgb[] = getDefaultRGBComponents(pixel); 461 return (getAlpha(pixel) << 24) 462 | (((int) (rgb[0] * 255.0f + 0.5f)) << 16) 463 | (((int) (rgb[1] * 255.0f + 0.5f)) << 8) 464 | (((int) (rgb[2] * 255.0f + 0.5f)) << 0); 465 } 466 467 /** 468 * Returns the red color component for the specified pixel, scaled 469 * from 0 to 255 in the default RGB <code>ColorSpace</code>, sRGB. A 470 * color conversion is done if necessary. The pixel value is specified 471 * by an array of data elements of type <code>transferType</code> passed 472 * in as an object reference. 473 * The returned value is a non pre-multiplied value. Thus, if the 474 * alpha is premultiplied, this method divides it out before returning 475 * the value. If the alpha value is 0, for example, the red value 476 * is 0. 477 * If <code>inData</code> is not a primitive array of type 478 * <code>transferType</code>, a <code>ClassCastException</code> is 479 * thrown. An <code>ArrayIndexOutOfBoundsException</code> is 480 * thrown if <code>inData</code> is not large enough to hold a 481 * pixel value for this <code>ColorModel</code>. Since 482 * <code>DirectColorModel</code> can be subclassed, subclasses inherit 483 * the implementation of this method and if they don't override it 484 * then they throw an exception if they use an unsupported 485 * <code>transferType</code>. 486 * An <code>UnsupportedOperationException</code> is thrown if this 487 * <code>transferType</code> is not supported by this 488 * <code>ColorModel</code>. 489 * @param inData the array containing the pixel value 490 * @return the value of the red component of the specified pixel. 491 * @throws ArrayIndexOutOfBoundsException if <code>inData</code> is not 492 * large enough to hold a pixel value for this color model 493 * @throws ClassCastException if <code>inData</code> is not a 494 * primitive array of type <code>transferType</code> 495 * @throws UnsupportedOperationException if this <code>transferType</code> 496 * is not supported by this color model 497 */ 498 public int getRed(Object inData) { 499 int pixel=0; 500 switch (transferType) { 501 case DataBuffer.TYPE_BYTE: 502 byte bdata[] = (byte[])inData; 503 pixel = bdata[0] & 0xff; 504 break; 505 case DataBuffer.TYPE_USHORT: 506 short sdata[] = (short[])inData; 507 pixel = sdata[0] & 0xffff; 508 break; 509 case DataBuffer.TYPE_INT: 510 int idata[] = (int[])inData; 511 pixel = idata[0]; 512 break; 513 default: 514 throw new UnsupportedOperationException("This method has not been "+ 515 "implemented for transferType " + transferType); 516 } 517 return getRed(pixel); 518 } 519 520 521 /** 522 * Returns the green color component for the specified pixel, scaled 523 * from 0 to 255 in the default RGB <code>ColorSpace</code>, sRGB. A 524 * color conversion is done if necessary. The pixel value is specified 525 * by an array of data elements of type <code>transferType</code> passed 526 * in as an object reference. 527 * The returned value is a non pre-multiplied value. Thus, if the 528 * alpha is premultiplied, this method divides it out before returning 529 * the value. If the alpha value is 0, for example, the green value 530 * is 0. If <code>inData</code> is not a primitive array of type 531 * <code>transferType</code>, a <code>ClassCastException</code> is thrown. 532 * An <code>ArrayIndexOutOfBoundsException</code> is 533 * thrown if <code>inData</code> is not large enough to hold a pixel 534 * value for this <code>ColorModel</code>. Since 535 * <code>DirectColorModel</code> can be subclassed, subclasses inherit 536 * the implementation of this method and if they don't override it 537 * then they throw an exception if they use an unsupported 538 * <code>transferType</code>. 539 * An <code>UnsupportedOperationException</code> is 540 * thrown if this <code>transferType</code> is not supported by this 541 * <code>ColorModel</code>. 542 * @param inData the array containing the pixel value 543 * @return the value of the green component of the specified pixel. 544 * @throws ArrayIndexOutOfBoundsException if <code>inData</code> is not 545 * large enough to hold a pixel value for this color model 546 * @throws ClassCastException if <code>inData</code> is not a 547 * primitive array of type <code>transferType</code> 548 * @throws UnsupportedOperationException if this <code>transferType</code> 549 * is not supported by this color model 550 */ 551 public int getGreen(Object inData) { 552 int pixel=0; 553 switch (transferType) { 554 case DataBuffer.TYPE_BYTE: 555 byte bdata[] = (byte[])inData; 556 pixel = bdata[0] & 0xff; 557 break; 558 case DataBuffer.TYPE_USHORT: 559 short sdata[] = (short[])inData; 560 pixel = sdata[0] & 0xffff; 561 break; 562 case DataBuffer.TYPE_INT: 563 int idata[] = (int[])inData; 564 pixel = idata[0]; 565 break; 566 default: 567 throw new UnsupportedOperationException("This method has not been "+ 568 "implemented for transferType " + transferType); 569 } 570 return getGreen(pixel); 571 } 572 573 574 /** 575 * Returns the blue color component for the specified pixel, scaled 576 * from 0 to 255 in the default RGB <code>ColorSpace</code>, sRGB. A 577 * color conversion is done if necessary. The pixel value is specified 578 * by an array of data elements of type <code>transferType</code> passed 579 * in as an object reference. 580 * The returned value is a non pre-multiplied value. Thus, if the 581 * alpha is premultiplied, this method divides it out before returning 582 * the value. If the alpha value is 0, for example, the blue value 583 * is 0. If <code>inData</code> is not a primitive array of type 584 * <code>transferType</code>, a <code>ClassCastException</code> is thrown. 585 * An <code>ArrayIndexOutOfBoundsException</code> is 586 * thrown if <code>inData</code> is not large enough to hold a pixel 587 * value for this <code>ColorModel</code>. Since 588 * <code>DirectColorModel</code> can be subclassed, subclasses inherit 589 * the implementation of this method and if they don't override it 590 * then they throw an exception if they use an unsupported 591 * <code>transferType</code>. 592 * An <code>UnsupportedOperationException</code> is 593 * thrown if this <code>transferType</code> is not supported by this 594 * <code>ColorModel</code>. 595 * @param inData the array containing the pixel value 596 * @return the value of the blue component of the specified pixel. 597 * @throws ArrayIndexOutOfBoundsException if <code>inData</code> is not 598 * large enough to hold a pixel value for this color model 599 * @throws ClassCastException if <code>inData</code> is not a 600 * primitive array of type <code>transferType</code> 601 * @throws UnsupportedOperationException if this <code>transferType</code> 602 * is not supported by this color model 603 */ 604 public int getBlue(Object inData) { 605 int pixel=0; 606 switch (transferType) { 607 case DataBuffer.TYPE_BYTE: 608 byte bdata[] = (byte[])inData; 609 pixel = bdata[0] & 0xff; 610 break; 611 case DataBuffer.TYPE_USHORT: 612 short sdata[] = (short[])inData; 613 pixel = sdata[0] & 0xffff; 614 break; 615 case DataBuffer.TYPE_INT: 616 int idata[] = (int[])inData; 617 pixel = idata[0]; 618 break; 619 default: 620 throw new UnsupportedOperationException("This method has not been "+ 621 "implemented for transferType " + transferType); 622 } 623 return getBlue(pixel); 624 } 625 626 /** 627 * Returns the alpha component for the specified pixel, scaled 628 * from 0 to 255. The pixel value is specified by an array of data 629 * elements of type <code>transferType</code> passed in as an object 630 * reference. 631 * If <code>inData</code> is not a primitive array of type 632 * <code>transferType</code>, a <code>ClassCastException</code> is 633 * thrown. An <code>ArrayIndexOutOfBoundsException</code> is 634 * thrown if <code>inData</code> is not large enough to hold a pixel 635 * value for this <code>ColorModel</code>. Since 636 * <code>DirectColorModel</code> can be subclassed, subclasses inherit 637 * the implementation of this method and if they don't override it 638 * then they throw an exception if they use an unsupported 639 * <code>transferType</code>. 640 * If this <code>transferType</code> is not supported, an 641 * <code>UnsupportedOperationException</code> is thrown. 642 * @param inData the specified pixel 643 * @return the alpha component of the specified pixel, scaled from 644 * 0 to 255. 645 * @exception <code>ClassCastException</code> if <code>inData</code> 646 * is not a primitive array of type <code>transferType</code> 647 * @exception <code>ArrayIndexOutOfBoundsException</code> if 648 * <code>inData</code> is not large enough to hold a pixel value 649 * for this <code>ColorModel</code> 650 * @exception <code>UnsupportedOperationException</code> if this 651 * <code>tranferType</code> is not supported by this 652 * <code>ColorModel</code> 653 */ 654 public int getAlpha(Object inData) { 655 int pixel=0; 656 switch (transferType) { 657 case DataBuffer.TYPE_BYTE: 658 byte bdata[] = (byte[])inData; 659 pixel = bdata[0] & 0xff; 660 break; 661 case DataBuffer.TYPE_USHORT: 662 short sdata[] = (short[])inData; 663 pixel = sdata[0] & 0xffff; 664 break; 665 case DataBuffer.TYPE_INT: 666 int idata[] = (int[])inData; 667 pixel = idata[0]; 668 break; 669 default: 670 throw new UnsupportedOperationException("This method has not been "+ 671 "implemented for transferType " + transferType); 672 } 673 return getAlpha(pixel); 674 } 675 676 /** 677 * Returns the color/alpha components for the specified pixel in the 678 * default RGB color model format. A color conversion is done if 679 * necessary. The pixel value is specified by an array of data 680 * elements of type <code>transferType</code> passed in as an object 681 * reference. If <code>inData</code> is not a primitive array of type 682 * <code>transferType</code>, a <code>ClassCastException</code> is 683 * thrown. An <code>ArrayIndexOutOfBoundsException</code> is 684 * thrown if <code>inData</code> is not large enough to hold a pixel 685 * value for this <code>ColorModel</code>. 686 * The returned value is in a non pre-multiplied format. Thus, if 687 * the alpha is premultiplied, this method divides it out of the 688 * color components. If the alpha value is 0, for example, the color 689 * values is 0. Since <code>DirectColorModel</code> can be 690 * subclassed, subclasses inherit the implementation of this method 691 * and if they don't override it then 692 * they throw an exception if they use an unsupported 693 * <code>transferType</code>. 694 * 695 * @param inData the specified pixel 696 * @return the color and alpha components of the specified pixel. 697 * @exception UnsupportedOperationException if this 698 * <code>transferType</code> is not supported by this 699 * <code>ColorModel</code> 700 * @see ColorModel#getRGBdefault 701 */ 702 public int getRGB(Object inData) { 703 int pixel=0; 704 switch (transferType) { 705 case DataBuffer.TYPE_BYTE: 706 byte bdata[] = (byte[])inData; 707 pixel = bdata[0] & 0xff; 708 break; 709 case DataBuffer.TYPE_USHORT: 710 short sdata[] = (short[])inData; 711 pixel = sdata[0] & 0xffff; 712 break; 713 case DataBuffer.TYPE_INT: 714 int idata[] = (int[])inData; 715 pixel = idata[0]; 716 break; 717 default: 718 throw new UnsupportedOperationException("This method has not been "+ 719 "implemented for transferType " + transferType); 720 } 721 return getRGB(pixel); 722 } 723 724 /** 725 * Returns a data element array representation of a pixel in this 726 * <code>ColorModel</code>, given an integer pixel representation in the 727 * default RGB color model. 728 * This array can then be passed to the <code>setDataElements</code> 729 * method of a <code>WritableRaster</code> object. If the pixel variable 730 * is <code>null</code>, a new array is allocated. If <code>pixel</code> 731 * is not <code>null</code>, it must be a primitive array of type 732 * <code>transferType</code>; otherwise, a 733 * <code>ClassCastException</code> is thrown. An 734 * <code>ArrayIndexOutOfBoundsException</code> is 735 * thrown if <code>pixel</code> is not large enough to hold a pixel 736 * value for this <code>ColorModel</code>. The pixel array is returned. 737 * Since <code>DirectColorModel</code> can be subclassed, subclasses 738 * inherit the implementation of this method and if they don't 739 * override it then they throw an exception if they use an unsupported 740 * <code>transferType</code>. 741 * 742 * @param rgb the integer pixel representation in the default RGB 743 * color model 744 * @param pixel the specified pixel 745 * @return an array representation of the specified pixel in this 746 * <code>ColorModel</code> 747 * @exception ClassCastException if <code>pixel</code> 748 * is not a primitive array of type <code>transferType</code> 749 * @exception ArrayIndexOutOfBoundsException if 750 * <code>pixel</code> is not large enough to hold a pixel value 751 * for this <code>ColorModel</code> 752 * @exception UnsupportedOperationException if this 753 * <code>transferType</code> is not supported by this 754 * <code>ColorModel</code> 755 * @see WritableRaster#setDataElements 756 * @see SampleModel#setDataElements 757 */ 758 public Object getDataElements(int rgb, Object pixel) { 759 //REMIND: maybe more efficient not to use int array for 760 //DataBuffer.TYPE_USHORT and DataBuffer.TYPE_INT 761 int intpixel[] = null; 762 if (transferType == DataBuffer.TYPE_INT && 763 pixel != null) { 764 intpixel = (int[])pixel; 765 intpixel[0] = 0; 766 } else { 767 intpixel = new int[1]; 768 } 769 770 ColorModel defaultCM = ColorModel.getRGBdefault(); 771 if (this == defaultCM || equals(defaultCM)) { 772 intpixel[0] = rgb; 773 return intpixel; 774 } 775 776 int red, grn, blu, alp; 777 red = (rgb>>16) & 0xff; 778 grn = (rgb>>8) & 0xff; 779 blu = rgb & 0xff; 780 if (is_sRGB || is_LinearRGB) { 781 int precision; 782 float factor; 783 if (is_LinearRGB) { 784 if (lRGBprecision == 8) { 785 red = fromsRGB8LUT8[red] & 0xff; 786 grn = fromsRGB8LUT8[grn] & 0xff; 787 blu = fromsRGB8LUT8[blu] & 0xff; 788 precision = 8; 789 factor = 1.0f / 255.0f; 790 } else { 791 red = fromsRGB8LUT16[red] & 0xffff; 792 grn = fromsRGB8LUT16[grn] & 0xffff; 793 blu = fromsRGB8LUT16[blu] & 0xffff; 794 precision = 16; 795 factor = 1.0f / 65535.0f; 796 } 797 } else { 798 precision = 8; 799 factor = 1.0f / 255.0f; 800 } 801 if (supportsAlpha) { 802 alp = (rgb>>24) & 0xff; 803 if (isAlphaPremultiplied) { 804 factor *= (alp * (1.0f / 255.0f)); 805 precision = -1; // force component calculations below 806 } 807 if (nBits[3] != 8) { 808 alp = (int) 809 ((alp * (1.0f / 255.0f) * ((1<<nBits[3]) - 1)) + 0.5f); 810 if (alp > ((1<<nBits[3]) - 1)) { 811 // fix 4412670 - see comment below 812 alp = (1<<nBits[3]) - 1; 813 } 814 } 815 intpixel[0] = alp << maskOffsets[3]; 816 } 817 if (nBits[0] != precision) { 818 red = (int) ((red * factor * ((1<<nBits[0]) - 1)) + 0.5f); 819 } 820 if (nBits[1] != precision) { 821 grn = (int) ((grn * factor * ((1<<nBits[1]) - 1)) + 0.5f); 822 } 823 if (nBits[2] != precision) { 824 blu = (int) ((blu * factor * ((1<<nBits[2]) - 1)) + 0.5f); 825 } 826 } else { 827 // Need to convert the color 828 float[] norm = new float[3]; 829 float factor = 1.0f / 255.0f; 830 norm[0] = red * factor; 831 norm[1] = grn * factor; 832 norm[2] = blu * factor; 833 norm = colorSpace.fromRGB(norm); 834 if (supportsAlpha) { 835 alp = (rgb>>24) & 0xff; 836 if (isAlphaPremultiplied) { 837 factor *= alp; 838 for (int i = 0; i < 3; i++) { 839 norm[i] *= factor; 840 } 841 } 842 if (nBits[3] != 8) { 843 alp = (int) 844 ((alp * (1.0f / 255.0f) * ((1<<nBits[3]) - 1)) + 0.5f); 845 if (alp > ((1<<nBits[3]) - 1)) { 846 // fix 4412670 - see comment below 847 alp = (1<<nBits[3]) - 1; 848 } 849 } 850 intpixel[0] = alp << maskOffsets[3]; 851 } 852 red = (int) ((norm[0] * ((1<<nBits[0]) - 1)) + 0.5f); 853 grn = (int) ((norm[1] * ((1<<nBits[1]) - 1)) + 0.5f); 854 blu = (int) ((norm[2] * ((1<<nBits[2]) - 1)) + 0.5f); 855 } 856 857 if (maxBits > 23) { 858 // fix 4412670 - for components of 24 or more bits 859 // some calculations done above with float precision 860 // may lose enough precision that the integer result 861 // overflows nBits, so we need to clamp. 862 if (red > ((1<<nBits[0]) - 1)) { 863 red = (1<<nBits[0]) - 1; 864 } 865 if (grn > ((1<<nBits[1]) - 1)) { 866 grn = (1<<nBits[1]) - 1; 867 } 868 if (blu > ((1<<nBits[2]) - 1)) { 869 blu = (1<<nBits[2]) - 1; 870 } 871 } 872 873 intpixel[0] |= (red << maskOffsets[0]) | 874 (grn << maskOffsets[1]) | 875 (blu << maskOffsets[2]); 876 877 switch (transferType) { 878 case DataBuffer.TYPE_BYTE: { 879 byte bdata[]; 880 if (pixel == null) { 881 bdata = new byte[1]; 882 } else { 883 bdata = (byte[])pixel; 884 } 885 bdata[0] = (byte)(0xff&intpixel[0]); 886 return bdata; 887 } 888 case DataBuffer.TYPE_USHORT:{ 889 short sdata[]; 890 if (pixel == null) { 891 sdata = new short[1]; 892 } else { 893 sdata = (short[])pixel; 894 } 895 sdata[0] = (short)(intpixel[0]&0xffff); 896 return sdata; 897 } 898 case DataBuffer.TYPE_INT: 899 return intpixel; 900 } 901 throw new UnsupportedOperationException("This method has not been "+ 902 "implemented for transferType " + transferType); 903 904 } 905 906 /** 907 * Returns an array of unnormalized color/alpha components given a pixel 908 * in this <code>ColorModel</code>. The pixel value is specified as an 909 * <code>int</code>. If the <code>components</code> array is 910 * <code>null</code>, a new array is allocated. The 911 * <code>components</code> array is returned. Color/alpha components are 912 * stored in the <code>components</code> array starting at 913 * <code>offset</code>, even if the array is allocated by this method. 914 * An <code>ArrayIndexOutOfBoundsException</code> is thrown if the 915 * <code>components</code> array is not <code>null</code> and is not large 916 * enough to hold all the color and alpha components, starting at 917 * <code>offset</code>. 918 * @param pixel the specified pixel 919 * @param components the array to receive the color and alpha 920 * components of the specified pixel 921 * @param offset the offset into the <code>components</code> array at 922 * which to start storing the color and alpha components 923 * @return an array containing the color and alpha components of the 924 * specified pixel starting at the specified offset. 925 */ 926 final public int[] getComponents(int pixel, int[] components, int offset) { 927 if (components == null) { 928 components = new int[offset+numComponents]; 929 } 930 931 for (int i=0; i < numComponents; i++) { 932 components[offset+i] = (pixel & maskArray[i]) >>> maskOffsets[i]; 933 } 934 935 return components; 936 } 937 938 /** 939 * Returns an array of unnormalized color/alpha components given a pixel 940 * in this <code>ColorModel</code>. The pixel value is specified by an 941 * array of data elements of type <code>transferType</code> passed in as 942 * an object reference. If <code>pixel</code> is not a primitive array 943 * of type <code>transferType</code>, a <code>ClassCastException</code> 944 * is thrown. An <code>ArrayIndexOutOfBoundsException</code> is 945 * thrown if <code>pixel</code> is not large enough to hold a 946 * pixel value for this <code>ColorModel</code>. If the 947 * <code>components</code> array is <code>null</code>, a new 948 * array is allocated. The <code>components</code> array is returned. 949 * Color/alpha components are stored in the <code>components</code> array 950 * starting at <code>offset</code>, even if the array is allocated by 951 * this method. An <code>ArrayIndexOutOfBoundsException</code> 952 * is thrown if the <code>components</code> array is not 953 * <code>null</code> and is not large enough to hold all the color and 954 * alpha components, starting at <code>offset</code>. 955 * Since <code>DirectColorModel</code> can be subclassed, subclasses 956 * inherit the implementation of this method and if they don't 957 * override it then they throw an exception if they use an unsupported 958 * <code>transferType</code>. 959 * @param pixel the specified pixel 960 * @param components the array to receive the color and alpha 961 * components of the specified pixel 962 * @param offset the offset into the <code>components</code> array at 963 * which to start storing the color and alpha components 964 * @return an array containing the color and alpha components of the 965 * specified pixel starting at the specified offset. 966 * @exception ClassCastException if <code>pixel</code> 967 * is not a primitive array of type <code>transferType</code> 968 * @exception ArrayIndexOutOfBoundsException if 969 * <code>pixel</code> is not large enough to hold a pixel value 970 * for this <code>ColorModel</code>, or if <code>components</code> 971 * is not <code>null</code> and is not large enough to hold all the 972 * color and alpha components, starting at <code>offset</code> 973 * @exception UnsupportedOperationException if this 974 * <code>transferType</code> is not supported by this 975 * color model 976 */ 977 final public int[] getComponents(Object pixel, int[] components, 978 int offset) { 979 int intpixel=0; 980 switch (transferType) { 981 case DataBuffer.TYPE_BYTE: 982 byte bdata[] = (byte[])pixel; 983 intpixel = bdata[0] & 0xff; 984 break; 985 case DataBuffer.TYPE_USHORT: 986 short sdata[] = (short[])pixel; 987 intpixel = sdata[0] & 0xffff; 988 break; 989 case DataBuffer.TYPE_INT: 990 int idata[] = (int[])pixel; 991 intpixel = idata[0]; 992 break; 993 default: 994 throw new UnsupportedOperationException("This method has not been "+ 995 "implemented for transferType " + transferType); 996 } 997 return getComponents(intpixel, components, offset); 998 } 999 1000 /** 1001 * Creates a <code>WritableRaster</code> with the specified width and 1002 * height that has a data layout (<code>SampleModel</code>) compatible 1003 * with this <code>ColorModel</code>. 1004 * @param w the width to apply to the new <code>WritableRaster</code> 1005 * @param h the height to apply to the new <code>WritableRaster</code> 1006 * @return a <code>WritableRaster</code> object with the specified 1007 * width and height. 1008 * @throws IllegalArgumentException if <code>w</code> or <code>h</code> 1009 * is less than or equal to zero 1010 * @see WritableRaster 1011 * @see SampleModel 1012 */ 1013 final public WritableRaster createCompatibleWritableRaster (int w, 1014 int h) { 1015 if ((w <= 0) || (h <= 0)) { 1016 throw new IllegalArgumentException("Width (" + w + ") and height (" + h + 1017 ") cannot be <= 0"); 1018 } 1019 int[] bandmasks; 1020 if (supportsAlpha) { 1021 bandmasks = new int[4]; 1022 bandmasks[3] = alpha_mask; 1023 } 1024 else { 1025 bandmasks = new int[3]; 1026 } 1027 bandmasks[0] = red_mask; 1028 bandmasks[1] = green_mask; 1029 bandmasks[2] = blue_mask; 1030 1031 if (pixel_bits > 16) { 1032 return Raster.createPackedRaster(DataBuffer.TYPE_INT, 1033 w,h,bandmasks,null); 1034 } 1035 else if (pixel_bits > 8) { 1036 return Raster.createPackedRaster(DataBuffer.TYPE_USHORT, 1037 w,h,bandmasks,null); 1038 } 1039 else { 1040 return Raster.createPackedRaster(DataBuffer.TYPE_BYTE, 1041 w,h,bandmasks,null); 1042 } 1043 } 1044 1045 /** 1046 * Returns a pixel value represented as an <code>int</code> in this 1047 * <code>ColorModel</code>, given an array of unnormalized color/alpha 1048 * components. An <code>ArrayIndexOutOfBoundsException</code> is 1049 * thrown if the <code>components</code> array is 1050 * not large enough to hold all the color and alpha components, starting 1051 * at <code>offset</code>. 1052 * @param components an array of unnormalized color and alpha 1053 * components 1054 * @param offset the index into <code>components</code> at which to 1055 * begin retrieving the color and alpha components 1056 * @return an <code>int</code> pixel value in this 1057 * <code>ColorModel</code> corresponding to the specified components. 1058 * @exception <code>ArrayIndexOutOfBoundsException</code> if 1059 * the <code>components</code> array is not large enough to 1060 * hold all of the color and alpha components starting at 1061 * <code>offset</code> 1062 */ 1063 public int getDataElement(int[] components, int offset) { 1064 int pixel = 0; 1065 for (int i=0; i < numComponents; i++) { 1066 pixel |= ((components[offset+i]<<maskOffsets[i])&maskArray[i]); 1067 } 1068 return pixel; 1069 } 1070 1071 /** 1072 * Returns a data element array representation of a pixel in this 1073 * <code>ColorModel</code>, given an array of unnormalized color/alpha 1074 * components. 1075 * This array can then be passed to the <code>setDataElements</code> 1076 * method of a <code>WritableRaster</code> object. 1077 * An <code>ArrayIndexOutOfBoundsException</code> is thrown if the 1078 * <code>components</code> array 1079 * is not large enough to hold all the color and alpha components, 1080 * starting at offset. If the <code>obj</code> variable is 1081 * <code>null</code>, a new array is allocated. If <code>obj</code> is 1082 * not <code>null</code>, it must be a primitive array 1083 * of type <code>transferType</code>; otherwise, a 1084 * <code>ClassCastException</code> is thrown. 1085 * An <code>ArrayIndexOutOfBoundsException</code> is thrown if 1086 * <code>obj</code> is not large enough to hold a pixel value for this 1087 * <code>ColorModel</code>. 1088 * Since <code>DirectColorModel</code> can be subclassed, subclasses 1089 * inherit the implementation of this method and if they don't 1090 * override it then they throw an exception if they use an unsupported 1091 * <code>transferType</code>. 1092 * @param components an array of unnormalized color and alpha 1093 * components 1094 * @param offset the index into <code>components</code> at which to 1095 * begin retrieving color and alpha components 1096 * @param obj the <code>Object</code> representing an array of color 1097 * and alpha components 1098 * @return an <code>Object</code> representing an array of color and 1099 * alpha components. 1100 * @exception <code>ClassCastException</code> if <code>obj</code> 1101 * is not a primitive array of type <code>transferType</code> 1102 * @exception <code>ArrayIndexOutOfBoundsException</code> if 1103 * <code>obj</code> is not large enough to hold a pixel value 1104 * for this <code>ColorModel</code> or the <code>components</code> 1105 * array is not large enough to hold all of the color and alpha 1106 * components starting at <code>offset</code> 1107 * @exception UnsupportedOperationException if this 1108 * <code>transferType</code> is not supported by this 1109 * color model 1110 * @see WritableRaster#setDataElements 1111 * @see SampleModel#setDataElements 1112 */ 1113 public Object getDataElements(int[] components, int offset, Object obj) { 1114 int pixel = 0; 1115 for (int i=0; i < numComponents; i++) { 1116 pixel |= ((components[offset+i]<<maskOffsets[i])&maskArray[i]); 1117 } 1118 switch (transferType) { 1119 case DataBuffer.TYPE_BYTE: 1120 if (obj instanceof byte[]) { 1121 byte bdata[] = (byte[])obj; 1122 bdata[0] = (byte)(pixel&0xff); 1123 return bdata; 1124 } else { 1125 byte bdata[] = {(byte)(pixel&0xff)}; 1126 return bdata; 1127 } 1128 case DataBuffer.TYPE_USHORT: 1129 if (obj instanceof short[]) { 1130 short sdata[] = (short[])obj; 1131 sdata[0] = (short)(pixel&0xffff); 1132 return sdata; 1133 } else { 1134 short sdata[] = {(short)(pixel&0xffff)}; 1135 return sdata; 1136 } 1137 case DataBuffer.TYPE_INT: 1138 if (obj instanceof int[]) { 1139 int idata[] = (int[])obj; 1140 idata[0] = pixel; 1141 return idata; 1142 } else { 1143 int idata[] = {pixel}; 1144 return idata; 1145 } 1146 default: 1147 throw new ClassCastException("This method has not been "+ 1148 "implemented for transferType " + transferType); 1149 } 1150 } 1151 1152 /** 1153 * Forces the raster data to match the state specified in the 1154 * <code>isAlphaPremultiplied</code> variable, assuming the data is 1155 * currently correctly described by this <code>ColorModel</code>. It 1156 * may multiply or divide the color raster data by alpha, or do 1157 * nothing if the data is in the correct state. If the data needs to 1158 * be coerced, this method will also return an instance of this 1159 * <code>ColorModel</code> with the <code>isAlphaPremultiplied</code> 1160 * flag set appropriately. This method will throw a 1161 * <code>UnsupportedOperationException</code> if this transferType is 1162 * not supported by this <code>ColorModel</code>. Since 1163 * <code>ColorModel</code> can be subclassed, subclasses inherit the 1164 * implementation of this method and if they don't override it then 1165 * they throw an exception if they use an unsupported transferType. 1166 * 1167 * @param raster the <code>WritableRaster</code> data 1168 * @param isAlphaPremultiplied <code>true</code> if the alpha is 1169 * premultiplied; <code>false</code> otherwise 1170 * @return a <code>ColorModel</code> object that represents the 1171 * coerced data. 1172 * @exception UnsupportedOperationException if this 1173 * <code>transferType</code> is not supported by this 1174 * color model 1175 */ 1176 final public ColorModel coerceData (WritableRaster raster, 1177 boolean isAlphaPremultiplied) 1178 { 1179 if (!supportsAlpha || 1180 this.isAlphaPremultiplied() == isAlphaPremultiplied) { 1181 return this; 1182 } 1183 1184 int w = raster.getWidth(); 1185 int h = raster.getHeight(); 1186 int aIdx = numColorComponents; 1187 float normAlpha; 1188 float alphaScale = 1.0f / ((float) ((1 << nBits[aIdx]) - 1)); 1189 1190 int rminX = raster.getMinX(); 1191 int rY = raster.getMinY(); 1192 int rX; 1193 int pixel[] = null; 1194 int zpixel[] = null; 1195 1196 if (isAlphaPremultiplied) { 1197 // Must mean that we are currently not premultiplied so 1198 // multiply by alpha 1199 switch (transferType) { 1200 case DataBuffer.TYPE_BYTE: { 1201 for (int y = 0; y < h; y++, rY++) { 1202 rX = rminX; 1203 for (int x = 0; x < w; x++, rX++) { 1204 pixel = raster.getPixel(rX, rY, pixel); 1205 normAlpha = pixel[aIdx] * alphaScale; 1206 if (normAlpha != 0.f) { 1207 for (int c=0; c < aIdx; c++) { 1208 pixel[c] = (int) (pixel[c] * normAlpha + 1209 0.5f); 1210 } 1211 raster.setPixel(rX, rY, pixel); 1212 } else { 1213 if (zpixel == null) { 1214 zpixel = new int[numComponents]; 1215 java.util.Arrays.fill(zpixel, 0); 1216 } 1217 raster.setPixel(rX, rY, zpixel); 1218 } 1219 } 1220 } 1221 } 1222 break; 1223 case DataBuffer.TYPE_USHORT: { 1224 for (int y = 0; y < h; y++, rY++) { 1225 rX = rminX; 1226 for (int x = 0; x < w; x++, rX++) { 1227 pixel = raster.getPixel(rX, rY, pixel); 1228 normAlpha = pixel[aIdx] * alphaScale; 1229 if (normAlpha != 0.f) { 1230 for (int c=0; c < aIdx; c++) { 1231 pixel[c] = (int) (pixel[c] * normAlpha + 1232 0.5f); 1233 } 1234 raster.setPixel(rX, rY, pixel); 1235 } else { 1236 if (zpixel == null) { 1237 zpixel = new int[numComponents]; 1238 java.util.Arrays.fill(zpixel, 0); 1239 } 1240 raster.setPixel(rX, rY, zpixel); 1241 } 1242 } 1243 } 1244 } 1245 break; 1246 case DataBuffer.TYPE_INT: { 1247 for (int y = 0; y < h; y++, rY++) { 1248 rX = rminX; 1249 for (int x = 0; x < w; x++, rX++) { 1250 pixel = raster.getPixel(rX, rY, pixel); 1251 normAlpha = pixel[aIdx] * alphaScale; 1252 if (normAlpha != 0.f) { 1253 for (int c=0; c < aIdx; c++) { 1254 pixel[c] = (int) (pixel[c] * normAlpha + 1255 0.5f); 1256 } 1257 raster.setPixel(rX, rY, pixel); 1258 } else { 1259 if (zpixel == null) { 1260 zpixel = new int[numComponents]; 1261 java.util.Arrays.fill(zpixel, 0); 1262 } 1263 raster.setPixel(rX, rY, zpixel); 1264 } 1265 } 1266 } 1267 } 1268 break; 1269 default: 1270 throw new UnsupportedOperationException("This method has not been "+ 1271 "implemented for transferType " + transferType); 1272 } 1273 } 1274 else { 1275 // We are premultiplied and want to divide it out 1276 switch (transferType) { 1277 case DataBuffer.TYPE_BYTE: { 1278 for (int y = 0; y < h; y++, rY++) { 1279 rX = rminX; 1280 for (int x = 0; x < w; x++, rX++) { 1281 pixel = raster.getPixel(rX, rY, pixel); 1282 normAlpha = pixel[aIdx] * alphaScale; 1283 if (normAlpha != 0.0f) { 1284 float invAlpha = 1.0f / normAlpha; 1285 for (int c=0; c < aIdx; c++) { 1286 pixel[c] = (int) (pixel[c] * invAlpha + 1287 0.5f); 1288 } 1289 raster.setPixel(rX, rY, pixel); 1290 } 1291 } 1292 } 1293 } 1294 break; 1295 case DataBuffer.TYPE_USHORT: { 1296 for (int y = 0; y < h; y++, rY++) { 1297 rX = rminX; 1298 for (int x = 0; x < w; x++, rX++) { 1299 pixel = raster.getPixel(rX, rY, pixel); 1300 normAlpha = pixel[aIdx] * alphaScale; 1301 if (normAlpha != 0) { 1302 float invAlpha = 1.0f / normAlpha; 1303 for (int c=0; c < aIdx; c++) { 1304 pixel[c] = (int) (pixel[c] * invAlpha + 1305 0.5f); 1306 } 1307 raster.setPixel(rX, rY, pixel); 1308 } 1309 } 1310 } 1311 } 1312 break; 1313 case DataBuffer.TYPE_INT: { 1314 for (int y = 0; y < h; y++, rY++) { 1315 rX = rminX; 1316 for (int x = 0; x < w; x++, rX++) { 1317 pixel = raster.getPixel(rX, rY, pixel); 1318 normAlpha = pixel[aIdx] * alphaScale; 1319 if (normAlpha != 0) { 1320 float invAlpha = 1.0f / normAlpha; 1321 for (int c=0; c < aIdx; c++) { 1322 pixel[c] = (int) (pixel[c] * invAlpha + 1323 0.5f); 1324 } 1325 raster.setPixel(rX, rY, pixel); 1326 } 1327 } 1328 } 1329 } 1330 break; 1331 default: 1332 throw new UnsupportedOperationException("This method has not been "+ 1333 "implemented for transferType " + transferType); 1334 } 1335 } 1336 1337 // Return a new color model 1338 return new DirectColorModel(colorSpace, pixel_bits, maskArray[0], 1339 maskArray[1], maskArray[2], maskArray[3], 1340 isAlphaPremultiplied, 1341 transferType); 1342 1343 } 1344 1345 /** 1346 * Returns <code>true</code> if <code>raster</code> is compatible 1347 * with this <code>ColorModel</code> and <code>false</code> if it is 1348 * not. 1349 * @param raster the {@link Raster} object to test for compatibility 1350 * @return <code>true</code> if <code>raster</code> is compatible 1351 * with this <code>ColorModel</code>; <code>false</code> otherwise. 1352 */ 1353 public boolean isCompatibleRaster(Raster raster) { 1354 SampleModel sm = raster.getSampleModel(); 1355 SinglePixelPackedSampleModel spsm; 1356 if (sm instanceof SinglePixelPackedSampleModel) { 1357 spsm = (SinglePixelPackedSampleModel) sm; 1358 } 1359 else { 1360 return false; 1361 } 1362 if (spsm.getNumBands() != getNumComponents()) { 1363 return false; 1364 } 1365 1366 int[] bitMasks = spsm.getBitMasks(); 1367 for (int i=0; i<numComponents; i++) { 1368 if (bitMasks[i] != maskArray[i]) { 1369 return false; 1370 } 1371 } 1372 1373 return (raster.getTransferType() == transferType); 1374 } 1375 1376 private void setFields() { 1377 // Set the private fields 1378 // REMIND: Get rid of these from the native code 1379 red_mask = maskArray[0]; 1380 red_offset = maskOffsets[0]; 1381 green_mask = maskArray[1]; 1382 green_offset = maskOffsets[1]; 1383 blue_mask = maskArray[2]; 1384 blue_offset = maskOffsets[2]; 1385 if (nBits[0] < 8) { 1386 red_scale = (1 << nBits[0]) - 1; 1387 } 1388 if (nBits[1] < 8) { 1389 green_scale = (1 << nBits[1]) - 1; 1390 } 1391 if (nBits[2] < 8) { 1392 blue_scale = (1 << nBits[2]) - 1; 1393 } 1394 if (supportsAlpha) { 1395 alpha_mask = maskArray[3]; 1396 alpha_offset = maskOffsets[3]; 1397 if (nBits[3] < 8) { 1398 alpha_scale = (1 << nBits[3]) - 1; 1399 } 1400 } 1401 } 1402 1403 /** 1404 * Returns a <code>String</code> that represents this 1405 * <code>DirectColorModel</code>. 1406 * @return a <code>String</code> representing this 1407 * <code>DirectColorModel</code>. 1408 */ 1409 public String toString() { 1410 return new String("DirectColorModel: rmask=" 1411 +Integer.toHexString(red_mask)+" gmask=" 1412 +Integer.toHexString(green_mask)+" bmask=" 1413 +Integer.toHexString(blue_mask)+" amask=" 1414 +Integer.toHexString(alpha_mask)); 1415 } 1416 }