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.util.Arrays; 25 26import org.apache.harmony.awt.internal.nls.Messages; 27 28/** 29 * The ComponentSampleModel class represents a set of image data whose each 30 * element - the sample of a pixel - takes one data element of the DataBuffer. 31 * <p> 32 * The Bank indices denote the correspondence between the bank of data buffers 33 * and a band of image data. The Pixel stride is the number of data array 34 * elements between two samples for the same band on the same scanline. The 35 * pixel stride for a BandedSampleModel is one. The scanline stride represents 36 * the number of data array elements between a specified sample and the 37 * corresponding sample in the same column in the next scanline. The array of 38 * band offsets gives the starting offsets within each data banks of the in the 39 * DataBuffer. The bank indices represents the indices within each bank of the 40 * DataBuffer corresponding to a band of image data. 41 * 42 * @since Android 1.0 43 */ 44public class ComponentSampleModel extends SampleModel { 45 46 /** 47 * The band offsets array of this ComponentSampleModel. 48 */ 49 protected int bandOffsets[]; 50 51 /** 52 * The bank indices array of this ComponentSampleModel. 53 */ 54 protected int bankIndices[]; 55 56 /** 57 * The number of bands in this ComponentSampleModel. 58 */ 59 protected int numBands; 60 61 /** 62 * The number banks of this ComponentSampleModel. 63 */ 64 protected int numBanks; 65 66 /** 67 * The scanline stride of this ComponentSampleModel. 68 */ 69 protected int scanlineStride; 70 71 /** 72 * The pixel stride of this ComponentSampleModel. 73 */ 74 protected int pixelStride; 75 76 /** 77 * Instantiates a new ComponentSampleModel with the specified properties. 78 * 79 * @param dataType 80 * the data type of samples. 81 * @param w 82 * the width of the image data. 83 * @param h 84 * the height of the image data. 85 * @param pixelStride 86 * the pixel stride of the image data. 87 * @param scanlineStride 88 * the scanline stride of the image data. 89 * @param bankIndices 90 * the array of the bank indices. 91 * @param bandOffsets 92 * the array of the band offsets. 93 */ 94 public ComponentSampleModel(int dataType, int w, int h, int pixelStride, int scanlineStride, 95 int bankIndices[], int bandOffsets[]) { 96 97 super(dataType, w, h, bandOffsets.length); 98 99 if (pixelStride < 0) { 100 // awt.24B=Pixel stride must be >= 0 101 throw new IllegalArgumentException(Messages.getString("awt.24B")); //$NON-NLS-1$ 102 } 103 104 if (scanlineStride < 0) { 105 // awt.24C=Scanline stride must be >= 0 106 throw new IllegalArgumentException(Messages.getString("awt.24C")); //$NON-NLS-1$ 107 } 108 109 if (bankIndices.length != bandOffsets.length) { 110 // awt.24D=Bank Indices length must be equal Bank Offsets length 111 throw new IllegalArgumentException(Messages.getString("awt.24D")); //$NON-NLS-1$ 112 } 113 114 this.pixelStride = pixelStride; 115 this.scanlineStride = scanlineStride; 116 this.bandOffsets = bandOffsets.clone(); 117 this.bankIndices = bankIndices.clone(); 118 this.numBands = bandOffsets.length; 119 120 int maxBank = 0; 121 for (int i = 0; i < bankIndices.length; i++) { 122 if (bankIndices[i] < 0) { 123 // awt.24E=Index of {0} bank must be >= 0 124 throw new IllegalArgumentException(Messages.getString("awt.24E", i)); //$NON-NLS-1$ 125 } 126 if (bankIndices[i] > maxBank) { 127 maxBank = bankIndices[i]; 128 } 129 } 130 this.numBanks = maxBank + 1; 131 132 } 133 134 /** 135 * Instantiates a new ComponentSampleModel with the specified properties. 136 * 137 * @param dataType 138 * the data type of the samples. 139 * @param w 140 * the width of the image data. 141 * @param h 142 * the height of the image data. 143 * @param pixelStride 144 * the pixel stride of the image data. 145 * @param scanlineStride 146 * the scanline stride of the image data. 147 * @param bandOffsets 148 * the band offsets. 149 */ 150 public ComponentSampleModel(int dataType, int w, int h, int pixelStride, int scanlineStride, 151 int bandOffsets[]) { 152 153 super(dataType, w, h, bandOffsets.length); 154 if (pixelStride < 0) { 155 // awt.24B=Pixel stride must be >= 0 156 throw new IllegalArgumentException(Messages.getString("awt.24B")); //$NON-NLS-1$ 157 } 158 159 if (scanlineStride < 0) { 160 // awt.24C=Scanline stride must be >= 0 161 throw new IllegalArgumentException(Messages.getString("awt.24C")); //$NON-NLS-1$ 162 } 163 164 this.pixelStride = pixelStride; 165 this.scanlineStride = scanlineStride; 166 this.bandOffsets = bandOffsets.clone(); 167 this.numBands = bandOffsets.length; 168 this.numBanks = 1; 169 170 this.bankIndices = new int[numBands]; 171 for (int i = 0; i < numBands; i++) { 172 bankIndices[i] = 0; 173 } 174 } 175 176 @Override 177 public Object getDataElements(int x, int y, Object obj, DataBuffer data) { 178 if (x < 0 || y < 0 || x >= this.width || y >= this.height) { 179 // awt.63=Coordinates are not in bounds 180 throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ 181 } 182 switch (dataType) { 183 case DataBuffer.TYPE_BYTE: 184 byte bdata[]; 185 if (obj == null) { 186 bdata = new byte[numBands]; 187 } else { 188 bdata = (byte[])obj; 189 } 190 191 for (int i = 0; i < numBands; i++) { 192 bdata[i] = (byte)getSample(x, y, i, data); 193 } 194 195 obj = bdata; 196 break; 197 198 case DataBuffer.TYPE_SHORT: 199 case DataBuffer.TYPE_USHORT: 200 short sdata[]; 201 if (obj == null) { 202 sdata = new short[numBands]; 203 } else { 204 sdata = (short[])obj; 205 } 206 207 for (int i = 0; i < numBands; i++) { 208 sdata[i] = (short)getSample(x, y, i, data); 209 } 210 211 obj = sdata; 212 break; 213 214 case DataBuffer.TYPE_INT: 215 int idata[]; 216 if (obj == null) { 217 idata = new int[numBands]; 218 } else { 219 idata = (int[])obj; 220 } 221 222 for (int i = 0; i < numBands; i++) { 223 idata[i] = getSample(x, y, i, data); 224 } 225 226 obj = idata; 227 break; 228 229 case DataBuffer.TYPE_FLOAT: 230 float fdata[]; 231 if (obj == null) { 232 fdata = new float[numBands]; 233 } else { 234 fdata = (float[])obj; 235 } 236 237 for (int i = 0; i < numBands; i++) { 238 fdata[i] = getSampleFloat(x, y, i, data); 239 } 240 241 obj = fdata; 242 break; 243 244 case DataBuffer.TYPE_DOUBLE: 245 double ddata[]; 246 if (obj == null) { 247 ddata = new double[numBands]; 248 } else { 249 ddata = (double[])obj; 250 } 251 252 for (int i = 0; i < numBands; i++) { 253 ddata[i] = getSampleDouble(x, y, i, data); 254 } 255 256 obj = ddata; 257 break; 258 } 259 260 return obj; 261 } 262 263 @Override 264 public void setDataElements(int x, int y, Object obj, DataBuffer data) { 265 if (x < 0 || y < 0 || x >= this.width || y >= this.height) { 266 // awt.63=Coordinates are not in bounds 267 throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ 268 } 269 switch (dataType) { 270 case DataBuffer.TYPE_BYTE: 271 byte barr[] = (byte[])obj; 272 for (int i = 0; i < numBands; i++) { 273 setSample(x, y, i, barr[i] & 0xff, data); 274 } 275 break; 276 277 case DataBuffer.TYPE_SHORT: 278 case DataBuffer.TYPE_USHORT: 279 short sarr[] = (short[])obj; 280 for (int i = 0; i < numBands; i++) { 281 setSample(x, y, i, sarr[i] & 0xffff, data); 282 } 283 break; 284 285 case DataBuffer.TYPE_INT: 286 int iarr[] = (int[])obj; 287 for (int i = 0; i < numBands; i++) { 288 setSample(x, y, i, iarr[i], data); 289 } 290 break; 291 292 case DataBuffer.TYPE_FLOAT: 293 float farr[] = (float[])obj; 294 for (int i = 0; i < numBands; i++) { 295 setSample(x, y, i, farr[i], data); 296 } 297 break; 298 299 case DataBuffer.TYPE_DOUBLE: 300 double darr[] = (double[])obj; 301 for (int i = 0; i < numBands; i++) { 302 setSample(x, y, i, darr[i], data); 303 } 304 break; 305 } 306 } 307 308 /** 309 * Compares this ComponentSampleModel with the specified Object. 310 * 311 * @param o 312 * the Object. 313 * @return true, if the object is a ComponentSampleModel with identical data 314 * values to this ComponentSampleModel, false otherwise. 315 */ 316 @Override 317 public boolean equals(Object o) { 318 if ((o == null) || !(o instanceof ComponentSampleModel)) { 319 return false; 320 } 321 ComponentSampleModel model = (ComponentSampleModel)o; 322 return this.width == model.width && this.height == model.height 323 && this.numBands == model.numBands && this.dataType == model.dataType 324 && Arrays.equals(this.bandOffsets, model.bandOffsets) 325 && Arrays.equals(this.bankIndices, model.bankIndices) 326 && this.numBands == model.numBands && this.numBanks == model.numBanks 327 && this.scanlineStride == model.scanlineStride 328 && this.pixelStride == model.pixelStride; 329 } 330 331 /** 332 * @see java.awt.image.SampleModel#createSubsetSampleModel(int[]) 333 */ 334 @Override 335 public SampleModel createSubsetSampleModel(int bands[]) { 336 if (bands.length > this.numBands) { 337 // awt.64=The number of the bands in the subset is greater than the 338 // number of bands in the sample model 339 throw new RasterFormatException(Messages.getString("awt.64")); //$NON-NLS-1$ 340 } 341 342 int indices[] = new int[bands.length]; 343 int offsets[] = new int[bands.length]; 344 345 for (int i = 0; i < bands.length; i++) { 346 indices[i] = bankIndices[bands[i]]; 347 offsets[i] = bandOffsets[bands[i]]; 348 } 349 350 return new ComponentSampleModel(dataType, width, height, pixelStride, scanlineStride, 351 indices, offsets); 352 353 } 354 355 @Override 356 public SampleModel createCompatibleSampleModel(int w, int h) { 357 return new ComponentSampleModel(dataType, w, h, pixelStride, pixelStride * w, bankIndices, 358 bandOffsets); 359 } 360 361 @Override 362 public int[] getPixel(int x, int y, int iArray[], DataBuffer data) { 363 int pixel[]; 364 365 if (iArray == null) { 366 pixel = new int[numBands]; 367 } else { 368 pixel = iArray; 369 } 370 371 for (int i = 0; i < numBands; i++) { 372 pixel[i] = getSample(x, y, i, data); 373 } 374 375 return pixel; 376 } 377 378 @Override 379 public void setPixel(int x, int y, int iArray[], DataBuffer data) { 380 for (int i = 0; i < numBands; i++) { 381 setSample(x, y, i, iArray[i], data); 382 } 383 } 384 385 @Override 386 public int getSample(int x, int y, int b, DataBuffer data) { 387 if (x < 0 || y < 0 || x >= this.width || y >= this.height) { 388 // awt.63=Coordinates are not in bounds 389 throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ 390 } 391 392 return data.getElem(bankIndices[b], y * scanlineStride + x * pixelStride + bandOffsets[b]); 393 } 394 395 @Override 396 public float getSampleFloat(int x, int y, int b, DataBuffer data) { 397 if (x < 0 || y < 0 || x >= this.width || y >= this.height) { 398 // awt.63=Coordinates are not in bounds 399 throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ 400 } 401 402 return data.getElemFloat(bankIndices[b], y * scanlineStride + x * pixelStride 403 + bandOffsets[b]); 404 } 405 406 @Override 407 public double getSampleDouble(int x, int y, int b, DataBuffer data) { 408 if (x < 0 || y < 0 || x >= this.width || y >= this.height) { 409 // awt.63=Coordinates are not in bounds 410 throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ 411 } 412 413 return data.getElemDouble(bankIndices[b], y * scanlineStride + x * pixelStride 414 + bandOffsets[b]); 415 } 416 417 @Override 418 public int[] getPixels(int x, int y, int w, int h, int iArray[], DataBuffer data) { 419 if (x < 0 || y < 0 || x > this.width || x + w > this.width || y > this.height 420 || y + h > this.height) { 421 // awt.63=Coordinates are not in bounds 422 throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ 423 } 424 int pixels[] = null; 425 int idx = 0; 426 427 if (iArray == null) { 428 pixels = new int[w * h * numBands]; 429 } else { 430 pixels = iArray; 431 } 432 433 for (int i = y; i < y + h; i++) { 434 for (int j = x; j < x + w; j++) { 435 for (int n = 0; n < numBands; n++) { 436 pixels[idx++] = getSample(j, i, n, data); 437 } 438 } 439 } 440 441 return pixels; 442 } 443 444 @Override 445 public void setPixels(int x, int y, int w, int h, int iArray[], DataBuffer data) { 446 if (x < 0 || y < 0 || x + w > this.width || y + h > this.height) { 447 // awt.63=Coordinates are not in bounds 448 throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ 449 } 450 int idx = 0; 451 for (int i = y; i < y + h; i++) { 452 for (int j = x; j < x + w; j++) { 453 for (int n = 0; n < numBands; n++) { 454 setSample(j, i, n, iArray[idx++], data); 455 } 456 } 457 } 458 } 459 460 @Override 461 public void setSample(int x, int y, int b, int s, DataBuffer data) { 462 if (x < 0 || y < 0 || x >= this.width || y >= this.height) { 463 // awt.63=Coordinates are not in bounds 464 throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ 465 } 466 467 data.setElem(bankIndices[b], y * scanlineStride + x * pixelStride + bandOffsets[b], s); 468 } 469 470 @Override 471 public int[] getSamples(int x, int y, int w, int h, int b, int iArray[], DataBuffer data) { 472 if (x < 0 || y < 0 || x + w > this.width || y + h > this.height) { 473 // awt.63=Coordinates are not in bounds 474 throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ 475 } 476 int samples[]; 477 int idx = 0; 478 479 if (iArray == null) { 480 samples = new int[w * h]; 481 } else { 482 samples = iArray; 483 } 484 485 if (data == null) { 486 // awt.295=data is null 487 throw new NullPointerException(Messages.getString("awt.295")); //$NON-NLS-1$ 488 } 489 490 for (int i = y; i < y + h; i++) { 491 for (int j = x; j < x + w; j++) { 492 samples[idx++] = getSample(j, i, b, data); 493 } 494 } 495 496 return samples; 497 } 498 499 @Override 500 public void setSamples(int x, int y, int w, int h, int b, int iArray[], DataBuffer data) { 501 if (x < 0 || y < 0 || x + w > this.width || y + h > this.height) { 502 // awt.63=Coordinates are not in bounds 503 throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ 504 } 505 int idx = 0; 506 for (int i = y; i < y + h; i++) { 507 for (int j = x; j < x + w; j++) { 508 setSample(j, i, b, iArray[idx++], data); 509 } 510 } 511 } 512 513 @Override 514 public void setSample(int x, int y, int b, float s, DataBuffer data) { 515 if (x < 0 || y < 0 || x >= this.width || y >= this.height) { 516 // awt.63=Coordinates are not in bounds 517 throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ 518 } 519 520 data.setElemFloat(bankIndices[b], y * scanlineStride + x * pixelStride + bandOffsets[b], s); 521 } 522 523 @Override 524 public void setSample(int x, int y, int b, double s, DataBuffer data) { 525 if (x < 0 || y < 0 || x >= this.width || y >= this.height) { 526 // awt.63=Coordinates are not in bounds 527 throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ 528 } 529 530 data 531 .setElemDouble(bankIndices[b], y * scanlineStride + x * pixelStride 532 + bandOffsets[b], s); 533 } 534 535 @Override 536 public DataBuffer createDataBuffer() { 537 DataBuffer data = null; 538 539 int maxOffset = bandOffsets[0]; 540 for (int i = 1; i < bandOffsets.length; i++) { 541 if (bandOffsets[i] > maxOffset) { 542 maxOffset = bandOffsets[i]; 543 } 544 } 545 int size = (height - 1) * scanlineStride + (width - 1) * pixelStride + maxOffset + 1; 546 547 switch (dataType) { 548 case DataBuffer.TYPE_BYTE: 549 data = new DataBufferByte(size, numBanks); 550 break; 551 case DataBuffer.TYPE_SHORT: 552 data = new DataBufferShort(size, numBanks); 553 break; 554 case DataBuffer.TYPE_USHORT: 555 data = new DataBufferUShort(size, numBanks); 556 break; 557 case DataBuffer.TYPE_INT: 558 data = new DataBufferInt(size, numBanks); 559 break; 560 case DataBuffer.TYPE_FLOAT: 561 data = new DataBufferFloat(size, numBanks); 562 break; 563 case DataBuffer.TYPE_DOUBLE: 564 data = new DataBufferDouble(size, numBanks); 565 break; 566 } 567 568 return data; 569 570 } 571 572 /** 573 * Gets the offset of the specified band of the specified pixel. 574 * 575 * @param x 576 * the X coordinate of the pixel. 577 * @param y 578 * the Y coordinate of the pixel. 579 * @param b 580 * the band. 581 * @return the offset of the specified band of the specified pixel. 582 */ 583 public int getOffset(int x, int y, int b) { 584 return y * scanlineStride + x * pixelStride + bandOffsets[b]; 585 } 586 587 /** 588 * Gets the offset of the first band of the specified pixel. 589 * 590 * @param x 591 * the X coordinate of pixel. 592 * @param y 593 * the Y coordinate of pixel. 594 * @return the offset of the first band of the specified pixel. 595 */ 596 public int getOffset(int x, int y) { 597 return y * scanlineStride + x * pixelStride + bandOffsets[0]; 598 } 599 600 @Override 601 public final int getSampleSize(int band) { 602 return DataBuffer.getDataTypeSize(dataType); 603 } 604 605 @Override 606 public final int[] getSampleSize() { 607 int sampleSizes[] = new int[numBands]; 608 int size = DataBuffer.getDataTypeSize(dataType); 609 610 for (int i = 0; i < numBands; i++) { 611 sampleSizes[i] = size; 612 } 613 return sampleSizes; 614 } 615 616 /** 617 * Gets an array of bank indices corresponding to this ComponentSampleModel. 618 * 619 * @return the array of bank indices. 620 */ 621 public final int[] getBankIndices() { 622 return bankIndices.clone(); 623 } 624 625 /** 626 * Gets an array of the band offsets corresponding to this 627 * ComponentSampleModel. 628 * 629 * @return the array of band offsets. 630 */ 631 public final int[] getBandOffsets() { 632 return bandOffsets.clone(); 633 } 634 635 /** 636 * Gets a hash code of this ComponentSampleModel object. 637 * 638 * @return a hash code of this ComponentSampleModel object. 639 */ 640 @Override 641 public int hashCode() { 642 int hash = 0; 643 int tmp = 0; 644 645 hash = width; 646 tmp = hash >>> 24; 647 hash <<= 8; 648 hash |= tmp; 649 hash ^= height; 650 tmp = hash >>> 24; 651 hash <<= 8; 652 hash |= tmp; 653 hash ^= numBands; 654 tmp = hash >>> 24; 655 hash <<= 8; 656 hash |= tmp; 657 hash ^= dataType; 658 tmp = hash >>> 24; 659 hash <<= 8; 660 hash |= tmp; 661 for (int element : bandOffsets) { 662 hash ^= element; 663 tmp = hash >>> 24; 664 hash <<= 8; 665 hash |= tmp; 666 } 667 for (int element : bankIndices) { 668 hash ^= element; 669 tmp = hash >>> 24; 670 hash <<= 8; 671 hash |= tmp; 672 } 673 hash ^= pixelStride; 674 tmp = hash >>> 24; 675 hash <<= 8; 676 hash |= tmp; 677 678 hash ^= scanlineStride; 679 return hash; 680 } 681 682 /** 683 * Gets the scanline stride of this ComponentSampleModel. 684 * 685 * @return the scanline stride of this ComponentSampleModel. 686 */ 687 public final int getScanlineStride() { 688 return scanlineStride; 689 } 690 691 /** 692 * Gets the pixel stride. 693 * 694 * @return the pixel stride. 695 */ 696 public final int getPixelStride() { 697 return pixelStride; 698 } 699 700 @Override 701 public final int getNumDataElements() { 702 return numBands; 703 } 704 705} 706