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 22package java.awt.image; 23 24import java.awt.Transparency; 25import java.awt.color.ColorSpace; 26import java.util.Arrays; 27 28import org.apache.harmony.awt.internal.nls.Messages; 29 30/** 31 * The class PackedColorModel represents a color model where the components are 32 * just the red, green, and blue bands, plus an alpha band if alpha is 33 * supported. 34 * 35 * @since Android 1.0 36 */ 37public abstract class PackedColorModel extends ColorModel { 38 39 /** 40 * The component masks. 41 */ 42 int componentMasks[]; 43 44 /** 45 * The offsets. 46 */ 47 int offsets[]; 48 49 /** 50 * The scales. 51 */ 52 float scales[]; 53 54 /** 55 * Instantiates a new packed color model. 56 * 57 * @param space 58 * the color space. 59 * @param bits 60 * the array of component masks. 61 * @param colorMaskArray 62 * the array that gives the bitmask corresponding to each color 63 * band (red, green, and blue). 64 * @param alphaMask 65 * the bitmask corresponding to the alpha band. 66 * @param isAlphaPremultiplied 67 * whether the alpha is pre-multiplied in this color model. 68 * @param trans 69 * the transparency strategy, @see java.awt.Transparency. 70 * @param transferType 71 * the transfer type (primitive java type to use for the 72 * components). 73 * @throws IllegalArgumentException 74 * if the number of bits in the combined bitmasks for the color 75 * bands is less than one or greater than 32. 76 */ 77 public PackedColorModel(ColorSpace space, int bits, int colorMaskArray[], int alphaMask, 78 boolean isAlphaPremultiplied, int trans, int transferType) { 79 80 super(bits, createBits(colorMaskArray, alphaMask), space, (alphaMask == 0 ? false : true), 81 isAlphaPremultiplied, trans, validateTransferType(transferType)); 82 83 if (pixel_bits < 1 || pixel_bits > 32) { 84 // awt.236=The bits is less than 1 or greater than 32 85 throw new IllegalArgumentException(Messages.getString("awt.236")); //$NON-NLS-1$ 86 } 87 88 componentMasks = new int[numComponents]; 89 for (int i = 0; i < numColorComponents; i++) { 90 componentMasks[i] = colorMaskArray[i]; 91 } 92 93 if (hasAlpha) { 94 componentMasks[numColorComponents] = alphaMask; 95 if (this.bits[numColorComponents] == 1) { 96 transparency = Transparency.BITMASK; 97 } 98 } 99 100 parseComponents(); 101 } 102 103 /** 104 * Instantiates a new packed color model. 105 * 106 * @param space 107 * the color space. 108 * @param bits 109 * the array of component masks. 110 * @param rmask 111 * the bitmask corresponding to the red band. 112 * @param gmask 113 * the bitmask corresponding to the green band. 114 * @param bmask 115 * the bitmask corresponding to the blue band. 116 * @param amask 117 * the bitmask corresponding to the alpha band. 118 * @param isAlphaPremultiplied 119 * whether the alpha is pre-multiplied in this color model. 120 * @param trans 121 * the transparency strategy, @see java.awt.Transparency. 122 * @param transferType 123 * the transfer type (primitive java type to use for the 124 * components). 125 * @throws IllegalArgumentException 126 * if the number of bits in the combined bitmasks for the color 127 * bands is less than one or greater than 32. 128 */ 129 public PackedColorModel(ColorSpace space, int bits, int rmask, int gmask, int bmask, int amask, 130 boolean isAlphaPremultiplied, int trans, int transferType) { 131 132 super(bits, createBits(rmask, gmask, bmask, amask), space, (amask == 0 ? false : true), 133 isAlphaPremultiplied, trans, validateTransferType(transferType)); 134 135 if (pixel_bits < 1 || pixel_bits > 32) { 136 // awt.236=The bits is less than 1 or greater than 32 137 throw new IllegalArgumentException(Messages.getString("awt.236")); //$NON-NLS-1$ 138 } 139 140 if (cs.getType() != ColorSpace.TYPE_RGB) { 141 // awt.239=The space is not a TYPE_RGB space 142 throw new IllegalArgumentException(Messages.getString("awt.239")); //$NON-NLS-1$ 143 } 144 145 for (int i = 0; i < numColorComponents; i++) { 146 if (cs.getMinValue(i) != 0.0f || cs.getMaxValue(i) != 1.0f) { 147 // awt.23A=The min/max normalized component values are not 148 // 0.0/1.0 149 throw new IllegalArgumentException(Messages.getString("awt.23A")); //$NON-NLS-1$ 150 } 151 } 152 componentMasks = new int[numComponents]; 153 componentMasks[0] = rmask; 154 componentMasks[1] = gmask; 155 componentMasks[2] = bmask; 156 157 if (hasAlpha) { 158 componentMasks[3] = amask; 159 if (this.bits[3] == 1) { 160 transparency = Transparency.BITMASK; 161 } 162 } 163 164 parseComponents(); 165 } 166 167 @Override 168 public WritableRaster getAlphaRaster(WritableRaster raster) { 169 if (!hasAlpha) { 170 return null; 171 } 172 173 int x = raster.getMinX(); 174 int y = raster.getMinY(); 175 int w = raster.getWidth(); 176 int h = raster.getHeight(); 177 int band[] = new int[1]; 178 band[0] = raster.getNumBands() - 1; 179 return raster.createWritableChild(x, y, w, h, x, y, band); 180 } 181 182 @Override 183 public boolean equals(Object obj) { 184 if (obj == null) { 185 return false; 186 } 187 if (!(obj instanceof PackedColorModel)) { 188 return false; 189 } 190 PackedColorModel cm = (PackedColorModel)obj; 191 192 return (pixel_bits == cm.getPixelSize() && transferType == cm.getTransferType() 193 && cs.getType() == cm.getColorSpace().getType() && hasAlpha == cm.hasAlpha() 194 && isAlphaPremultiplied == cm.isAlphaPremultiplied() 195 && transparency == cm.getTransparency() 196 && numColorComponents == cm.getNumColorComponents() 197 && numComponents == cm.getNumComponents() 198 && Arrays.equals(bits, cm.getComponentSize()) && Arrays.equals(componentMasks, cm 199 .getMasks())); 200 } 201 202 @Override 203 public boolean isCompatibleSampleModel(SampleModel sm) { 204 if (sm == null) { 205 return false; 206 } 207 if (!(sm instanceof SinglePixelPackedSampleModel)) { 208 return false; 209 } 210 SinglePixelPackedSampleModel esm = (SinglePixelPackedSampleModel)sm; 211 212 return ((esm.getNumBands() == numComponents) && (esm.getTransferType() == transferType) && Arrays 213 .equals(esm.getBitMasks(), componentMasks)); 214 } 215 216 @Override 217 public SampleModel createCompatibleSampleModel(int w, int h) { 218 return new SinglePixelPackedSampleModel(transferType, w, h, componentMasks); 219 } 220 221 /** 222 * Gets the bitmask corresponding to the specified color component. 223 * 224 * @param index 225 * the index of the desired color. 226 * @return the mask. 227 */ 228 public final int getMask(int index) { 229 return componentMasks[index]; 230 } 231 232 /** 233 * Gets the bitmasks of the components. 234 * 235 * @return the masks. 236 */ 237 public final int[] getMasks() { 238 return (componentMasks.clone()); 239 } 240 241 /** 242 * Creates the bits. 243 * 244 * @param colorMaskArray 245 * the color mask array. 246 * @param alphaMask 247 * the alpha mask. 248 * @return the int[]. 249 */ 250 private static int[] createBits(int colorMaskArray[], int alphaMask) { 251 int bits[]; 252 int numComp; 253 if (alphaMask == 0) { 254 numComp = colorMaskArray.length; 255 } else { 256 numComp = colorMaskArray.length + 1; 257 } 258 259 bits = new int[numComp]; 260 int i = 0; 261 for (; i < colorMaskArray.length; i++) { 262 bits[i] = countCompBits(colorMaskArray[i]); 263 if (bits[i] < 0) { 264 // awt.23B=The mask of the {0} component is not contiguous 265 throw new IllegalArgumentException(Messages.getString("awt.23B", i)); //$NON-NLS-1$ 266 } 267 } 268 269 if (i < numComp) { 270 bits[i] = countCompBits(alphaMask); 271 272 if (bits[i] < 0) { 273 // awt.23C=The mask of the alpha component is not contiguous 274 throw new IllegalArgumentException(Messages.getString("awt.23C")); //$NON-NLS-1$ 275 } 276 } 277 278 return bits; 279 } 280 281 /** 282 * Creates the bits. 283 * 284 * @param rmask 285 * the rmask. 286 * @param gmask 287 * the gmask. 288 * @param bmask 289 * the bmask. 290 * @param amask 291 * the amask. 292 * @return the int[]. 293 */ 294 private static int[] createBits(int rmask, int gmask, int bmask, int amask) { 295 296 int numComp; 297 if (amask == 0) { 298 numComp = 3; 299 } else { 300 numComp = 4; 301 } 302 int bits[] = new int[numComp]; 303 304 bits[0] = countCompBits(rmask); 305 if (bits[0] < 0) { 306 // awt.23D=The mask of the red component is not contiguous 307 throw new IllegalArgumentException(Messages.getString("awt.23D")); //$NON-NLS-1$ 308 } 309 310 bits[1] = countCompBits(gmask); 311 if (bits[1] < 0) { 312 // awt.23E=The mask of the green component is not contiguous 313 throw new IllegalArgumentException(Messages.getString("awt.23E")); //$NON-NLS-1$ 314 } 315 316 bits[2] = countCompBits(bmask); 317 if (bits[2] < 0) { 318 // awt.23F=The mask of the blue component is not contiguous 319 throw new IllegalArgumentException(Messages.getString("awt.23F")); //$NON-NLS-1$ 320 } 321 322 if (amask != 0) { 323 bits[3] = countCompBits(amask); 324 if (bits[3] < 0) { 325 // awt.23C=The mask of the alpha component is not contiguous 326 throw new IllegalArgumentException(Messages.getString("awt.23C")); //$NON-NLS-1$ 327 } 328 } 329 330 return bits; 331 } 332 333 /** 334 * Count comp bits. 335 * 336 * @param compMask 337 * the comp mask. 338 * @return the int. 339 */ 340 private static int countCompBits(int compMask) { 341 int bits = 0; 342 if (compMask != 0) { 343 // Deleting final zeros 344 while ((compMask & 1) == 0) { 345 compMask >>>= 1; 346 } 347 // Counting component bits 348 while ((compMask & 1) == 1) { 349 compMask >>>= 1; 350 bits++; 351 } 352 } 353 354 if (compMask != 0) { 355 return -1; 356 } 357 358 return bits; 359 } 360 361 /** 362 * Validate transfer type. 363 * 364 * @param transferType 365 * the transfer type. 366 * @return the int. 367 */ 368 private static int validateTransferType(int transferType) { 369 if (transferType != DataBuffer.TYPE_BYTE && transferType != DataBuffer.TYPE_USHORT 370 && transferType != DataBuffer.TYPE_INT) { 371 // awt.240=The transferType not is one of DataBuffer.TYPE_BYTE, 372 // DataBuffer.TYPE_USHORT or DataBuffer.TYPE_INT 373 throw new IllegalArgumentException(Messages.getString("awt.240")); //$NON-NLS-1$ 374 } 375 return transferType; 376 } 377 378 /** 379 * Parses the components. 380 */ 381 private void parseComponents() { 382 offsets = new int[numComponents]; 383 scales = new float[numComponents]; 384 for (int i = 0; i < numComponents; i++) { 385 int off = 0; 386 int mask = componentMasks[i]; 387 while ((mask & 1) == 0) { 388 mask >>>= 1; 389 off++; 390 } 391 offsets[i] = off; 392 if (bits[i] == 0) { 393 scales[i] = 256.0f; // May be any value different from zero, 394 // because will dividing by zero 395 } else { 396 scales[i] = 255.0f / maxValues[i]; 397 } 398 } 399 400 } 401 402} 403