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.util.Arrays; 25 26 import org.apache.harmony.awt.internal.nls.Messages; 27 28 /** 29 * The SinglePixelPackedSampleModel class represents pixel data where several 30 * samples combine to create a single pixel and are stored in a single data 31 * array element. This class supports TYPE_BYTE, TYPE_USHORT, TYPE_INT data 32 * types. 33 * 34 * @since Android 1.0 35 */ 36 public class SinglePixelPackedSampleModel extends SampleModel { 37 38 /** 39 * The bit masks. 40 */ 41 private int bitMasks[]; 42 43 /** 44 * The bit offsets. 45 */ 46 private int bitOffsets[]; 47 48 /** 49 * The bit sizes. 50 */ 51 private int bitSizes[]; 52 53 /** 54 * The scanline stride. 55 */ 56 private int scanlineStride; 57 58 /** 59 * The max bit size. 60 */ 61 private int maxBitSize; 62 63 /** 64 * Instantiates a new SinglePixelPackedSampleModel with the specified 65 * parameters. 66 * 67 * @param dataType 68 * the data type of samples. 69 * @param w 70 * the width of the image data. 71 * @param h 72 * the height of the image data. 73 * @param bitMasks 74 * the bit masks for all the bands. 75 */ 76 public SinglePixelPackedSampleModel(int dataType, int w, int h, int bitMasks[]) { 77 this(dataType, w, h, w, bitMasks); 78 } 79 80 /** 81 * Instantiates a new SinglePixelPackedSampleModel with the specified 82 * parameters. 83 * 84 * @param dataType 85 * the data type of the samples. 86 * @param w 87 * the width of the image data. 88 * @param h 89 * the height of the image data. 90 * @param scanlineStride 91 * the scanline stride of the image data. 92 * @param bitMasks 93 * the bit masks for all the bands. 94 */ 95 public SinglePixelPackedSampleModel(int dataType, int w, int h, int scanlineStride, 96 int bitMasks[]) { 97 98 super(dataType, w, h, bitMasks.length); 99 100 if (dataType != DataBuffer.TYPE_BYTE && dataType != DataBuffer.TYPE_USHORT 101 && dataType != DataBuffer.TYPE_INT) { 102 // awt.61=Unsupported data type: {0} 103 throw new IllegalArgumentException(Messages.getString("awt.61", //$NON-NLS-1$ 104 dataType)); 105 } 106 107 this.scanlineStride = scanlineStride; 108 this.bitMasks = bitMasks.clone(); 109 this.bitOffsets = new int[this.numBands]; 110 this.bitSizes = new int[this.numBands]; 111 112 this.maxBitSize = 0; 113 114 for (int i = 0; i < this.numBands; i++) { 115 int offset = 0; 116 int size = 0; 117 int mask = bitMasks[i]; 118 119 if (mask != 0) { 120 while ((mask & 1) == 0) { 121 mask >>>= 1; 122 offset++; 123 } 124 125 while ((mask & 1) == 1) { 126 mask >>>= 1; 127 size++; 128 } 129 130 if (mask != 0) { 131 // awt.62=Wrong mask : {0} 132 throw new IllegalArgumentException(Messages.getString("awt.62", bitMasks[i])); //$NON-NLS-1$ 133 } 134 } 135 136 this.bitOffsets[i] = offset; 137 this.bitSizes[i] = size; 138 139 if (this.maxBitSize < size) { 140 this.maxBitSize = size; 141 } 142 143 } 144 145 } 146 147 @Override 148 public Object getDataElements(int x, int y, Object obj, DataBuffer data) { 149 if (x < 0 || y < 0 || x >= this.width || y >= this.height) { 150 // awt.63=Coordinates are not in bounds 151 throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ 152 } 153 switch (getTransferType()) { 154 case DataBuffer.TYPE_BYTE: 155 byte bdata[]; 156 if (obj == null) { 157 bdata = new byte[1]; 158 } else { 159 bdata = (byte[])obj; 160 } 161 162 bdata[0] = (byte)data.getElem(y * scanlineStride + x); 163 obj = bdata; 164 break; 165 case DataBuffer.TYPE_USHORT: 166 short sdata[]; 167 if (obj == null) { 168 sdata = new short[1]; 169 } else { 170 sdata = (short[])obj; 171 } 172 173 sdata[0] = (short)data.getElem(y * scanlineStride + x); 174 obj = sdata; 175 break; 176 case DataBuffer.TYPE_INT: 177 int idata[]; 178 if (obj == null) { 179 idata = new int[1]; 180 } else { 181 idata = (int[])obj; 182 } 183 184 idata[0] = data.getElem(y * scanlineStride + x); 185 obj = idata; 186 break; 187 } 188 return obj; 189 } 190 191 @Override 192 public void setDataElements(int x, int y, Object obj, DataBuffer data) { 193 if (x < 0 || y < 0 || x >= this.width || y >= this.height) { 194 // awt.63=Coordinates are not in bounds 195 throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ 196 } 197 switch (getTransferType()) { 198 case DataBuffer.TYPE_BYTE: 199 data.setElem(y * scanlineStride + x, ((byte[])obj)[0] & 0xff); 200 break; 201 case DataBuffer.TYPE_USHORT: 202 data.setElem(y * scanlineStride + x, ((short[])obj)[0] & 0xffff); 203 break; 204 case DataBuffer.TYPE_INT: 205 data.setElem(y * scanlineStride + x, ((int[])obj)[0]); 206 break; 207 } 208 } 209 210 /** 211 * Compares this SinglePixelPackedSampleModel object with the specified 212 * object. 213 * 214 * @param o 215 * the Object to be compared. 216 * @return true, if this SinglePixelPackedSampleModel object is equal to the 217 * specified object, false otherwise. 218 */ 219 @Override 220 public boolean equals(Object o) { 221 if ((o == null) || !(o instanceof SinglePixelPackedSampleModel)) { 222 return false; 223 } 224 225 SinglePixelPackedSampleModel model = (SinglePixelPackedSampleModel)o; 226 return this.width == model.width && this.height == model.height 227 && this.numBands == model.numBands && this.dataType == model.dataType 228 && Arrays.equals(this.bitMasks, model.bitMasks) 229 && Arrays.equals(this.bitOffsets, model.bitOffsets) 230 && Arrays.equals(this.bitSizes, model.bitSizes) 231 && this.scanlineStride == model.scanlineStride; 232 } 233 234 @Override 235 public SampleModel createSubsetSampleModel(int bands[]) { 236 if (bands.length > this.numBands) { 237 // awt.64=The number of the bands in the subset is greater than the 238 // number of bands in the sample model 239 throw new RasterFormatException(Messages.getString("awt.64")); //$NON-NLS-1$ 240 } 241 242 int masks[] = new int[bands.length]; 243 for (int i = 0; i < bands.length; i++) { 244 masks[i] = this.bitMasks[bands[i]]; 245 } 246 return new SinglePixelPackedSampleModel(this.dataType, this.width, this.height, 247 this.scanlineStride, masks); 248 } 249 250 @Override 251 public SampleModel createCompatibleSampleModel(int w, int h) { 252 return new SinglePixelPackedSampleModel(this.dataType, w, h, this.bitMasks); 253 } 254 255 @Override 256 public int[] getPixel(int x, int y, int iArray[], DataBuffer data) { 257 if (x < 0 || y < 0 || x >= this.width || y >= this.height) { 258 // awt.63=Coordinates are not in bounds 259 throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ 260 } 261 int pixel[]; 262 if (iArray == null) { 263 pixel = new int[this.numBands]; 264 } else { 265 pixel = iArray; 266 } 267 268 for (int i = 0; i < this.numBands; i++) { 269 pixel[i] = getSample(x, y, i, data); 270 } 271 272 return pixel; 273 } 274 275 @Override 276 public void setPixel(int x, int y, int iArray[], DataBuffer data) { 277 if (x < 0 || y < 0 || x >= this.width || y >= this.height) { 278 // awt.63=Coordinates are not in bounds 279 throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ 280 } 281 for (int i = 0; i < this.numBands; i++) { 282 setSample(x, y, i, iArray[i], data); 283 } 284 } 285 286 @Override 287 public int getSample(int x, int y, int b, DataBuffer data) { 288 if (x < 0 || y < 0 || x >= this.width || y >= this.height) { 289 // awt.63=Coordinates are not in bounds 290 throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ 291 } 292 int sample = data.getElem(y * scanlineStride + x); 293 return ((sample & this.bitMasks[b]) >>> this.bitOffsets[b]); 294 } 295 296 @Override 297 public int[] getPixels(int x, int y, int w, int h, int iArray[], DataBuffer data) { 298 if ((x < 0) || (y < 0) || ((long)x + (long)w > this.width) 299 || ((long)y + (long)h > this.height)) { 300 // awt.63=Coordinates are not in bounds 301 throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ 302 } 303 304 int pixels[]; 305 306 if (iArray == null) { 307 pixels = new int[w * h * this.numBands]; 308 } else { 309 pixels = iArray; 310 } 311 312 int idx = 0; 313 314 for (int i = y; i < y + h; i++) { 315 for (int j = x; j < x + w; j++) { 316 for (int n = 0; n < this.numBands; n++) { 317 pixels[idx++] = getSample(j, i, n, data); 318 } 319 } 320 } 321 return pixels; 322 } 323 324 @Override 325 public void setPixels(int x, int y, int w, int h, int iArray[], DataBuffer data) { 326 if ((x < 0) || (y < 0) || ((long)x + (long)w > this.width) 327 || ((long)y + (long)h > this.height)) { 328 // awt.63=Coordinates are not in bounds 329 throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ 330 } 331 332 int idx = 0; 333 334 for (int i = y; i < y + h; i++) { 335 for (int j = x; j < x + w; j++) { 336 for (int n = 0; n < this.numBands; n++) { 337 setSample(j, i, n, iArray[idx++], data); 338 } 339 } 340 } 341 } 342 343 @Override 344 public void setSample(int x, int y, int b, int s, DataBuffer data) { 345 if (x < 0 || y < 0 || x >= this.width || y >= this.height) { 346 // awt.63=Coordinates are not in bounds 347 throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ 348 } 349 int tmp = data.getElem(y * scanlineStride + x); 350 tmp &= ~this.bitMasks[b]; 351 tmp |= (s << this.bitOffsets[b]) & this.bitMasks[b]; 352 data.setElem(y * scanlineStride + x, tmp); 353 } 354 355 @Override 356 public int[] getSamples(int x, int y, int w, int h, int b, int iArray[], DataBuffer data) { 357 if ((x < 0) || (y < 0) || ((long)x + (long)w > this.width) 358 || ((long)y + (long)h > this.height)) { 359 // awt.63=Coordinates are not in bounds 360 throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ 361 } 362 363 int samples[]; 364 int idx = 0; 365 366 if (iArray == null) { 367 samples = new int[w * h]; 368 } else { 369 samples = iArray; 370 } 371 372 for (int i = y; i < y + h; i++) { 373 for (int j = x; j < x + w; j++) { 374 samples[idx++] = getSample(j, i, b, data); 375 } 376 } 377 378 return samples; 379 } 380 381 @Override 382 public void setSamples(int x, int y, int w, int h, int b, int iArray[], DataBuffer data) { 383 if ((x < 0) || (y < 0) || ((long)x + (long)w > this.width) 384 || ((long)y + (long)h > this.height)) { 385 // awt.63=Coordinates are not in bounds 386 throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ 387 } 388 389 int idx = 0; 390 for (int i = y; i < y + h; i++) { 391 for (int j = x; j < x + w; j++) { 392 setSample(x + j, y + i, b, iArray[idx++], data); 393 } 394 } 395 } 396 397 @Override 398 public DataBuffer createDataBuffer() { 399 DataBuffer data = null; 400 int size = (this.height - 1) * scanlineStride + width; 401 402 switch (this.dataType) { 403 case DataBuffer.TYPE_BYTE: 404 data = new DataBufferByte(size); 405 break; 406 case DataBuffer.TYPE_USHORT: 407 data = new DataBufferUShort(size); 408 break; 409 case DataBuffer.TYPE_INT: 410 data = new DataBufferInt(size); 411 break; 412 } 413 return data; 414 } 415 416 /** 417 * Gets the offset of the specified pixel in the data array. 418 * 419 * @param x 420 * the X coordinate of the specified pixel. 421 * @param y 422 * the Y coordinate of the specified pixel. 423 * @return the offset of the specified pixel. 424 */ 425 public int getOffset(int x, int y) { 426 return (y * scanlineStride + x); 427 } 428 429 @Override 430 public int getSampleSize(int band) { 431 return bitSizes[band]; 432 } 433 434 @Override 435 public int[] getSampleSize() { 436 return bitSizes.clone(); 437 } 438 439 /** 440 * Gets an array of the bit offsets of the data array elements. 441 * 442 * @return an array of the bit offsets. 443 */ 444 public int[] getBitOffsets() { 445 return bitOffsets.clone(); 446 } 447 448 /** 449 * Gets an array of the bit masks for all bands. 450 * 451 * @return an array of the bit masks for all bands. 452 */ 453 public int[] getBitMasks() { 454 return bitMasks.clone(); 455 } 456 457 /** 458 * Returns a hash code of this MultiPixelPackedSampleModel class. 459 * 460 * @return the hash code of this MultiPixelPackedSampleModel class. 461 */ 462 @Override 463 public int hashCode() { 464 int hash = 0; 465 int tmp = 0; 466 467 hash = width; 468 tmp = hash >>> 24; 469 hash <<= 8; 470 hash |= tmp; 471 hash ^= height; 472 tmp = hash >>> 24; 473 hash <<= 8; 474 hash |= tmp; 475 hash ^= numBands; 476 tmp = hash >>> 24; 477 hash <<= 8; 478 hash |= tmp; 479 hash ^= dataType; 480 tmp = hash >>> 24; 481 hash <<= 8; 482 hash |= tmp; 483 for (int element : bitMasks) { 484 hash ^= element; 485 tmp = hash >>> 24; 486 hash <<= 8; 487 hash |= tmp; 488 } 489 for (int element : bitOffsets) { 490 hash ^= element; 491 tmp = hash >>> 24; 492 hash <<= 8; 493 hash |= tmp; 494 } 495 for (int element : bitSizes) { 496 hash ^= element; 497 tmp = hash >>> 24; 498 hash <<= 8; 499 hash |= tmp; 500 } 501 hash ^= scanlineStride; 502 return hash; 503 } 504 505 /** 506 * Gets the scanline stride. 507 * 508 * @return the scanline stride 509 */ 510 public int getScanlineStride() { 511 return this.scanlineStride; 512 } 513 514 @Override 515 public int getNumDataElements() { 516 return 1; 517 } 518 519 } 520