1 /* 2 * Copyright (c) 1997, 2014, 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 /* **************************************************************** 27 ****************************************************************** 28 ****************************************************************** 29 *** COPYRIGHT (c) Eastman Kodak Company, 1997 30 *** As an unpublished work pursuant to Title 17 of the United 31 *** States Code. All rights reserved. 32 ****************************************************************** 33 ****************************************************************** 34 ******************************************************************/ 35 36 package java.awt.image; 37 38 import java.util.Arrays; 39 40 /** 41 * This class represents image data which is stored such that each sample 42 * of a pixel occupies one data element of the DataBuffer. It stores the 43 * N samples which make up a pixel in N separate data array elements. 44 * Different bands may be in different banks of the DataBuffer. 45 * Accessor methods are provided so that image data can be manipulated 46 * directly. This class can support different kinds of interleaving, e.g. 47 * band interleaving, scanline interleaving, and pixel interleaving. 48 * Pixel stride is the number of data array elements between two samples 49 * for the same band on the same scanline. Scanline stride is the number 50 * of data array elements between a given sample and the corresponding sample 51 * in the same column of the next scanline. Band offsets denote the number 52 * of data array elements from the first data array element of the bank 53 * of the DataBuffer holding each band to the first sample of the band. 54 * The bands are numbered from 0 to N-1. This class can represent image 55 * data for which each sample is an unsigned integral number which can be 56 * stored in 8, 16, or 32 bits (using <code>DataBuffer.TYPE_BYTE</code>, 57 * <code>DataBuffer.TYPE_USHORT</code>, or <code>DataBuffer.TYPE_INT</code>, 58 * respectively), data for which each sample is a signed integral number 59 * which can be stored in 16 bits (using <code>DataBuffer.TYPE_SHORT</code>), 60 * or data for which each sample is a signed float or double quantity 61 * (using <code>DataBuffer.TYPE_FLOAT</code> or 62 * <code>DataBuffer.TYPE_DOUBLE</code>, respectively). 63 * All samples of a given ComponentSampleModel 64 * are stored with the same precision. All strides and offsets must be 65 * non-negative. This class supports 66 * {@link DataBuffer#TYPE_BYTE TYPE_BYTE}, 67 * {@link DataBuffer#TYPE_USHORT TYPE_USHORT}, 68 * {@link DataBuffer#TYPE_SHORT TYPE_SHORT}, 69 * {@link DataBuffer#TYPE_INT TYPE_INT}, 70 * {@link DataBuffer#TYPE_FLOAT TYPE_FLOAT}, 71 * {@link DataBuffer#TYPE_DOUBLE TYPE_DOUBLE}, 72 * @see java.awt.image.PixelInterleavedSampleModel 73 * @see java.awt.image.BandedSampleModel 74 */ 75 76 public class ComponentSampleModel extends SampleModel 77 { 78 /** Offsets for all bands in data array elements. */ 79 protected int bandOffsets[]; 80 81 /** Index for each bank storing a band of image data. */ 82 protected int[] bankIndices; 83 84 /** 85 * The number of bands in this 86 * <code>ComponentSampleModel</code>. 87 */ 88 protected int numBands = 1; 89 90 /** 91 * The number of banks in this 92 * <code>ComponentSampleModel</code>. 93 */ 94 protected int numBanks = 1; 95 96 /** 97 * Line stride (in data array elements) of the region of image 98 * data described by this ComponentSampleModel. 99 */ 100 protected int scanlineStride; 101 102 /** Pixel stride (in data array elements) of the region of image 103 * data described by this ComponentSampleModel. 104 */ 105 protected int pixelStride; 106 107 static private native void initIDs(); 108 static { 109 ColorModel.loadLibraries(); 110 initIDs(); 111 } 112 113 /** 114 * Constructs a ComponentSampleModel with the specified parameters. 115 * The number of bands will be given by the length of the bandOffsets array. 116 * All bands will be stored in the first bank of the DataBuffer. 117 * @param dataType the data type for storing samples 118 * @param w the width (in pixels) of the region of 119 * image data described 120 * @param h the height (in pixels) of the region of 121 * image data described 122 * @param pixelStride the pixel stride of the region of image 123 * data described 124 * @param scanlineStride the line stride of the region of image 125 * data described 126 * @param bandOffsets the offsets of all bands 127 * @throws IllegalArgumentException if <code>w</code> or 128 * <code>h</code> is not greater than 0 129 * @throws IllegalArgumentException if <code>pixelStride</code> 130 * is less than 0 131 * @throws IllegalArgumentException if <code>scanlineStride</code> 132 * is less than 0 133 * @throws IllegalArgumentException if <code>numBands</code> 134 * is less than 1 135 * @throws IllegalArgumentException if the product of <code>w</code> 136 * and <code>h</code> is greater than 137 * <code>Integer.MAX_VALUE</code> 138 * @throws IllegalArgumentException if <code>dataType</code> is not 139 * one of the supported data types 140 */ 141 public ComponentSampleModel(int dataType, 142 int w, int h, 143 int pixelStride, 144 int scanlineStride, 145 int bandOffsets[]) { 146 super(dataType, w, h, bandOffsets.length); 147 this.dataType = dataType; 148 this.pixelStride = pixelStride; 149 this.scanlineStride = scanlineStride; 150 this.bandOffsets = bandOffsets.clone(); 151 numBands = this.bandOffsets.length; 152 if (pixelStride < 0) { 153 throw new IllegalArgumentException("Pixel stride must be >= 0"); 154 } 155 // TODO - bug 4296691 - remove this check 156 if (scanlineStride < 0) { 157 throw new IllegalArgumentException("Scanline stride must be >= 0"); 158 } 159 if (numBands < 1) { 160 throw new IllegalArgumentException("Must have at least one band."); 161 } 162 if ((dataType < DataBuffer.TYPE_BYTE) || 163 (dataType > DataBuffer.TYPE_DOUBLE)) { 164 throw new IllegalArgumentException("Unsupported dataType."); 165 } 166 bankIndices = new int[numBands]; 167 for (int i=0; i<numBands; i++) { 168 bankIndices[i] = 0; 169 } 170 verify(); 171 } 172 173 174 /** 175 * Constructs a ComponentSampleModel with the specified parameters. 176 * The number of bands will be given by the length of the bandOffsets array. 177 * Different bands may be stored in different banks of the DataBuffer. 178 * 179 * @param dataType the data type for storing samples 180 * @param w the width (in pixels) of the region of 181 * image data described 182 * @param h the height (in pixels) of the region of 183 * image data described 184 * @param pixelStride the pixel stride of the region of image 185 * data described 186 * @param scanlineStride The line stride of the region of image 187 * data described 188 * @param bankIndices the bank indices of all bands 189 * @param bandOffsets the band offsets of all bands 190 * @throws IllegalArgumentException if <code>w</code> or 191 * <code>h</code> is not greater than 0 192 * @throws IllegalArgumentException if <code>pixelStride</code> 193 * is less than 0 194 * @throws IllegalArgumentException if <code>scanlineStride</code> 195 * is less than 0 196 * @throws IllegalArgumentException if the length of 197 * <code>bankIndices</code> does not equal the length of 198 * <code>bankOffsets</code> 199 * @throws IllegalArgumentException if any of the bank indices 200 * of <code>bandIndices</code> is less than 0 201 * @throws IllegalArgumentException if <code>dataType</code> is not 202 * one of the supported data types 203 */ 204 public ComponentSampleModel(int dataType, 205 int w, int h, 206 int pixelStride, 207 int scanlineStride, 208 int bankIndices[], 209 int bandOffsets[]) { 210 super(dataType, w, h, bandOffsets.length); 211 this.dataType = dataType; 212 this.pixelStride = pixelStride; 213 this.scanlineStride = scanlineStride; 214 this.bandOffsets = bandOffsets.clone(); 215 this.bankIndices = bankIndices.clone(); 216 if (pixelStride < 0) { 217 throw new IllegalArgumentException("Pixel stride must be >= 0"); 218 } 219 // TODO - bug 4296691 - remove this check 220 if (scanlineStride < 0) { 221 throw new IllegalArgumentException("Scanline stride must be >= 0"); 222 } 223 if ((dataType < DataBuffer.TYPE_BYTE) || 224 (dataType > DataBuffer.TYPE_DOUBLE)) { 225 throw new IllegalArgumentException("Unsupported dataType."); 226 } 227 int maxBank = this.bankIndices[0]; 228 if (maxBank < 0) { 229 throw new IllegalArgumentException("Index of bank 0 is less than "+ 230 "0 ("+maxBank+")"); 231 } 232 for (int i=1; i < this.bankIndices.length; i++) { 233 if (this.bankIndices[i] > maxBank) { 234 maxBank = this.bankIndices[i]; 235 } 236 else if (this.bankIndices[i] < 0) { 237 throw new IllegalArgumentException("Index of bank "+i+ 238 " is less than 0 ("+ 239 maxBank+")"); 240 } 241 } 242 numBanks = maxBank+1; 243 numBands = this.bandOffsets.length; 244 if (this.bandOffsets.length != this.bankIndices.length) { 245 throw new IllegalArgumentException("Length of bandOffsets must "+ 246 "equal length of bankIndices."); 247 } 248 verify(); 249 } 250 251 private void verify() { 252 int requiredSize = getBufferSize(); 253 } 254 255 /** 256 * Returns the size of the data buffer (in data elements) needed 257 * for a data buffer that matches this ComponentSampleModel. 258 */ 259 private int getBufferSize() { 260 int maxBandOff=bandOffsets[0]; 261 for (int i=1; i<bandOffsets.length; i++) { 262 maxBandOff = Math.max(maxBandOff,bandOffsets[i]); 263 } 264 265 if (maxBandOff < 0 || maxBandOff > (Integer.MAX_VALUE - 1)) { 266 throw new IllegalArgumentException("Invalid band offset"); 267 } 268 269 if (pixelStride < 0 || pixelStride > (Integer.MAX_VALUE / width)) { 270 throw new IllegalArgumentException("Invalid pixel stride"); 271 } 272 273 if (scanlineStride < 0 || scanlineStride > (Integer.MAX_VALUE / height)) { 274 throw new IllegalArgumentException("Invalid scanline stride"); 275 } 276 277 int size = maxBandOff + 1; 278 279 int val = pixelStride * (width - 1); 280 281 if (val > (Integer.MAX_VALUE - size)) { 282 throw new IllegalArgumentException("Invalid pixel stride"); 283 } 284 285 size += val; 286 287 val = scanlineStride * (height - 1); 288 289 if (val > (Integer.MAX_VALUE - size)) { 290 throw new IllegalArgumentException("Invalid scan stride"); 291 } 292 293 size += val; 294 295 return size; 296 } 297 298 /** 299 * Preserves band ordering with new step factor... 300 */ 301 int []orderBands(int orig[], int step) { 302 int map[] = new int[orig.length]; 303 int ret[] = new int[orig.length]; 304 305 for (int i=0; i<map.length; i++) map[i] = i; 306 307 for (int i = 0; i < ret.length; i++) { 308 int index = i; 309 for (int j = i+1; j < ret.length; j++) { 310 if (orig[map[index]] > orig[map[j]]) { 311 index = j; 312 } 313 } 314 ret[map[index]] = i*step; 315 map[index] = map[i]; 316 } 317 return ret; 318 } 319 320 /** 321 * Creates a new <code>ComponentSampleModel</code> with the specified 322 * width and height. The new <code>SampleModel</code> will have the same 323 * number of bands, storage data type, interleaving scheme, and 324 * pixel stride as this <code>SampleModel</code>. 325 * @param w the width of the resulting <code>SampleModel</code> 326 * @param h the height of the resulting <code>SampleModel</code> 327 * @return a new <code>ComponentSampleModel</code> with the specified size 328 * @throws IllegalArgumentException if <code>w</code> or 329 * <code>h</code> is not greater than 0 330 */ 331 public SampleModel createCompatibleSampleModel(int w, int h) { 332 SampleModel ret=null; 333 long size; 334 int minBandOff=bandOffsets[0]; 335 int maxBandOff=bandOffsets[0]; 336 for (int i=1; i<bandOffsets.length; i++) { 337 minBandOff = Math.min(minBandOff,bandOffsets[i]); 338 maxBandOff = Math.max(maxBandOff,bandOffsets[i]); 339 } 340 maxBandOff -= minBandOff; 341 342 int bands = bandOffsets.length; 343 int bandOff[]; 344 int pStride = Math.abs(pixelStride); 345 int lStride = Math.abs(scanlineStride); 346 int bStride = Math.abs(maxBandOff); 347 348 if (pStride > lStride) { 349 if (pStride > bStride) { 350 if (lStride > bStride) { // pix > line > band 351 bandOff = new int[bandOffsets.length]; 352 for (int i=0; i<bands; i++) 353 bandOff[i] = bandOffsets[i]-minBandOff; 354 lStride = bStride+1; 355 pStride = lStride*h; 356 } else { // pix > band > line 357 bandOff = orderBands(bandOffsets,lStride*h); 358 pStride = bands*lStride*h; 359 } 360 } else { // band > pix > line 361 pStride = lStride*h; 362 bandOff = orderBands(bandOffsets,pStride*w); 363 } 364 } else { 365 if (pStride > bStride) { // line > pix > band 366 bandOff = new int[bandOffsets.length]; 367 for (int i=0; i<bands; i++) 368 bandOff[i] = bandOffsets[i]-minBandOff; 369 pStride = bStride+1; 370 lStride = pStride*w; 371 } else { 372 if (lStride > bStride) { // line > band > pix 373 bandOff = orderBands(bandOffsets,pStride*w); 374 lStride = bands*pStride*w; 375 } else { // band > line > pix 376 lStride = pStride*w; 377 bandOff = orderBands(bandOffsets,lStride*h); 378 } 379 } 380 } 381 382 // make sure we make room for negative offsets... 383 int base = 0; 384 if (scanlineStride < 0) { 385 base += lStride*h; 386 lStride *= -1; 387 } 388 if (pixelStride < 0) { 389 base += pStride*w; 390 pStride *= -1; 391 } 392 393 for (int i=0; i<bands; i++) 394 bandOff[i] += base; 395 return new ComponentSampleModel(dataType, w, h, pStride, 396 lStride, bankIndices, bandOff); 397 } 398 399 /** 400 * Creates a new ComponentSampleModel with a subset of the bands 401 * of this ComponentSampleModel. The new ComponentSampleModel can be 402 * used with any DataBuffer that the existing ComponentSampleModel 403 * can be used with. The new ComponentSampleModel/DataBuffer 404 * combination will represent an image with a subset of the bands 405 * of the original ComponentSampleModel/DataBuffer combination. 406 * @param bands a subset of bands from this 407 * <code>ComponentSampleModel</code> 408 * @return a <code>ComponentSampleModel</code> created with a subset 409 * of bands from this <code>ComponentSampleModel</code>. 410 */ 411 public SampleModel createSubsetSampleModel(int bands[]) { 412 if (bands.length > bankIndices.length) 413 throw new RasterFormatException("There are only " + 414 bankIndices.length + 415 " bands"); 416 int newBankIndices[] = new int[bands.length]; 417 int newBandOffsets[] = new int[bands.length]; 418 419 for (int i=0; i<bands.length; i++) { 420 newBankIndices[i] = bankIndices[bands[i]]; 421 newBandOffsets[i] = bandOffsets[bands[i]]; 422 } 423 424 return new ComponentSampleModel(this.dataType, width, height, 425 this.pixelStride, 426 this.scanlineStride, 427 newBankIndices, newBandOffsets); 428 } 429 430 /** 431 * Creates a <code>DataBuffer</code> that corresponds to this 432 * <code>ComponentSampleModel</code>. 433 * The <code>DataBuffer</code> object's data type, number of banks, 434 * and size are be consistent with this <code>ComponentSampleModel</code>. 435 * @return a <code>DataBuffer</code> whose data type, number of banks 436 * and size are consistent with this 437 * <code>ComponentSampleModel</code>. 438 */ 439 public DataBuffer createDataBuffer() { 440 DataBuffer dataBuffer = null; 441 442 int size = getBufferSize(); 443 switch (dataType) { 444 case DataBuffer.TYPE_BYTE: 445 dataBuffer = new DataBufferByte(size, numBanks); 446 break; 447 case DataBuffer.TYPE_USHORT: 448 dataBuffer = new DataBufferUShort(size, numBanks); 449 break; 450 case DataBuffer.TYPE_SHORT: 451 dataBuffer = new DataBufferShort(size, numBanks); 452 break; 453 case DataBuffer.TYPE_INT: 454 dataBuffer = new DataBufferInt(size, numBanks); 455 break; 456 case DataBuffer.TYPE_FLOAT: 457 dataBuffer = new DataBufferFloat(size, numBanks); 458 break; 459 case DataBuffer.TYPE_DOUBLE: 460 dataBuffer = new DataBufferDouble(size, numBanks); 461 break; 462 } 463 464 return dataBuffer; 465 } 466 467 468 /** Gets the offset for the first band of pixel (x,y). 469 * A sample of the first band can be retrieved from a 470 * <code>DataBuffer</code> 471 * <code>data</code> with a <code>ComponentSampleModel</code> 472 * <code>csm</code> as 473 * <pre> 474 * data.getElem(csm.getOffset(x, y)); 475 * </pre> 476 * @param x the X location of the pixel 477 * @param y the Y location of the pixel 478 * @return the offset for the first band of the specified pixel. 479 */ 480 public int getOffset(int x, int y) { 481 int offset = y*scanlineStride + x*pixelStride + bandOffsets[0]; 482 return offset; 483 } 484 485 /** Gets the offset for band b of pixel (x,y). 486 * A sample of band <code>b</code> can be retrieved from a 487 * <code>DataBuffer</code> <code>data</code> 488 * with a <code>ComponentSampleModel</code> <code>csm</code> as 489 * <pre> 490 * data.getElem(csm.getOffset(x, y, b)); 491 * </pre> 492 * @param x the X location of the specified pixel 493 * @param y the Y location of the specified pixel 494 * @param b the specified band 495 * @return the offset for the specified band of the specified pixel. 496 */ 497 public int getOffset(int x, int y, int b) { 498 int offset = y*scanlineStride + x*pixelStride + bandOffsets[b]; 499 return offset; 500 } 501 502 /** Returns the number of bits per sample for all bands. 503 * @return an array containing the number of bits per sample 504 * for all bands, where each element in the array 505 * represents a band. 506 */ 507 public final int[] getSampleSize() { 508 int sampleSize[] = new int [numBands]; 509 int sizeInBits = getSampleSize(0); 510 511 for (int i=0; i<numBands; i++) 512 sampleSize[i] = sizeInBits; 513 514 return sampleSize; 515 } 516 517 /** Returns the number of bits per sample for the specified band. 518 * @param band the specified band 519 * @return the number of bits per sample for the specified band. 520 */ 521 public final int getSampleSize(int band) { 522 return DataBuffer.getDataTypeSize(dataType); 523 } 524 525 /** Returns the bank indices for all bands. 526 * @return the bank indices for all bands. 527 */ 528 public final int [] getBankIndices() { 529 return bankIndices.clone(); 530 } 531 532 /** Returns the band offset for all bands. 533 * @return the band offsets for all bands. 534 */ 535 public final int [] getBandOffsets() { 536 return bandOffsets.clone(); 537 } 538 539 /** Returns the scanline stride of this ComponentSampleModel. 540 * @return the scanline stride of this <code>ComponentSampleModel</code>. 541 */ 542 public final int getScanlineStride() { 543 return scanlineStride; 544 } 545 546 /** Returns the pixel stride of this ComponentSampleModel. 547 * @return the pixel stride of this <code>ComponentSampleModel</code>. 548 */ 549 public final int getPixelStride() { 550 return pixelStride; 551 } 552 553 /** 554 * Returns the number of data elements needed to transfer a pixel 555 * with the 556 * {@link #getDataElements(int, int, Object, DataBuffer) } and 557 * {@link #setDataElements(int, int, Object, DataBuffer) } 558 * methods. 559 * For a <code>ComponentSampleModel</code>, this is identical to the 560 * number of bands. 561 * @return the number of data elements needed to transfer a pixel with 562 * the <code>getDataElements</code> and 563 * <code>setDataElements</code> methods. 564 * @see java.awt.image.SampleModel#getNumDataElements 565 * @see #getNumBands 566 */ 567 public final int getNumDataElements() { 568 return getNumBands(); 569 } 570 571 /** 572 * Returns data for a single pixel in a primitive array of type 573 * <code>TransferType</code>. For a <code>ComponentSampleModel</code>, 574 * this is the same as the data type, and samples are returned 575 * one per array element. Generally, <code>obj</code> should 576 * be passed in as <code>null</code>, so that the <code>Object</code> 577 * is created automatically and is the right primitive data type. 578 * <p> 579 * The following code illustrates transferring data for one pixel from 580 * <code>DataBuffer</code> <code>db1</code>, whose storage layout is 581 * described by <code>ComponentSampleModel</code> <code>csm1</code>, 582 * to <code>DataBuffer</code> <code>db2</code>, whose storage layout 583 * is described by <code>ComponentSampleModel</code> <code>csm2</code>. 584 * The transfer is usually more efficient than using 585 * <code>getPixel</code> and <code>setPixel</code>. 586 * <pre> 587 * ComponentSampleModel csm1, csm2; 588 * DataBufferInt db1, db2; 589 * csm2.setDataElements(x, y, 590 * csm1.getDataElements(x, y, null, db1), db2); 591 * </pre> 592 * 593 * Using <code>getDataElements</code> and <code>setDataElements</code> 594 * to transfer between two <code>DataBuffer/SampleModel</code> 595 * pairs is legitimate if the <code>SampleModel</code> objects have 596 * the same number of bands, corresponding bands have the same number of 597 * bits per sample, and the <code>TransferType</code>s are the same. 598 * <p> 599 * If <code>obj</code> is not <code>null</code>, it should be a 600 * primitive array of type <code>TransferType</code>. 601 * Otherwise, a <code>ClassCastException</code> is thrown. An 602 * <code>ArrayIndexOutOfBoundsException</code> might be thrown if the 603 * coordinates are not in bounds, or if <code>obj</code> is not 604 * <code>null</code> and is not large enough to hold 605 * the pixel data. 606 * 607 * @param x the X coordinate of the pixel location 608 * @param y the Y coordinate of the pixel location 609 * @param obj if non-<code>null</code>, a primitive array 610 * in which to return the pixel data 611 * @param data the <code>DataBuffer</code> containing the image data 612 * @return the data of the specified pixel 613 * @see #setDataElements(int, int, Object, DataBuffer) 614 * 615 * @throws NullPointerException if data is null. 616 * @throws ArrayIndexOutOfBoundsException if the coordinates are 617 * not in bounds, or if obj is too small to hold the output. 618 */ 619 public Object getDataElements(int x, int y, Object obj, DataBuffer data) { 620 if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) { 621 throw new ArrayIndexOutOfBoundsException 622 ("Coordinate out of bounds!"); 623 } 624 625 int type = getTransferType(); 626 int numDataElems = getNumDataElements(); 627 int pixelOffset = y*scanlineStride + x*pixelStride; 628 629 switch(type) { 630 631 case DataBuffer.TYPE_BYTE: 632 633 byte[] bdata; 634 635 if (obj == null) 636 bdata = new byte[numDataElems]; 637 else 638 bdata = (byte[])obj; 639 640 for (int i=0; i<numDataElems; i++) { 641 bdata[i] = (byte)data.getElem(bankIndices[i], 642 pixelOffset + bandOffsets[i]); 643 } 644 645 obj = (Object)bdata; 646 break; 647 648 case DataBuffer.TYPE_USHORT: 649 case DataBuffer.TYPE_SHORT: 650 651 short[] sdata; 652 653 if (obj == null) 654 sdata = new short[numDataElems]; 655 else 656 sdata = (short[])obj; 657 658 for (int i=0; i<numDataElems; i++) { 659 sdata[i] = (short)data.getElem(bankIndices[i], 660 pixelOffset + bandOffsets[i]); 661 } 662 663 obj = (Object)sdata; 664 break; 665 666 case DataBuffer.TYPE_INT: 667 668 int[] idata; 669 670 if (obj == null) 671 idata = new int[numDataElems]; 672 else 673 idata = (int[])obj; 674 675 for (int i=0; i<numDataElems; i++) { 676 idata[i] = data.getElem(bankIndices[i], 677 pixelOffset + bandOffsets[i]); 678 } 679 680 obj = (Object)idata; 681 break; 682 683 case DataBuffer.TYPE_FLOAT: 684 685 float[] fdata; 686 687 if (obj == null) 688 fdata = new float[numDataElems]; 689 else 690 fdata = (float[])obj; 691 692 for (int i=0; i<numDataElems; i++) { 693 fdata[i] = data.getElemFloat(bankIndices[i], 694 pixelOffset + bandOffsets[i]); 695 } 696 697 obj = (Object)fdata; 698 break; 699 700 case DataBuffer.TYPE_DOUBLE: 701 702 double[] ddata; 703 704 if (obj == null) 705 ddata = new double[numDataElems]; 706 else 707 ddata = (double[])obj; 708 709 for (int i=0; i<numDataElems; i++) { 710 ddata[i] = data.getElemDouble(bankIndices[i], 711 pixelOffset + bandOffsets[i]); 712 } 713 714 obj = (Object)ddata; 715 break; 716 } 717 718 return obj; 719 } 720 721 /** 722 * Returns all samples for the specified pixel in an int array, 723 * one sample per array element. 724 * An <code>ArrayIndexOutOfBoundsException</code> might be thrown if 725 * the coordinates are not in bounds. 726 * @param x the X coordinate of the pixel location 727 * @param y the Y coordinate of the pixel location 728 * @param iArray If non-null, returns the samples in this array 729 * @param data The DataBuffer containing the image data 730 * @return the samples of the specified pixel. 731 * @see #setPixel(int, int, int[], DataBuffer) 732 * 733 * @throws NullPointerException if data is null. 734 * @throws ArrayIndexOutOfBoundsException if the coordinates are 735 * not in bounds, or if iArray is too small to hold the output. 736 */ 737 public int[] getPixel(int x, int y, int iArray[], DataBuffer data) { 738 if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) { 739 throw new ArrayIndexOutOfBoundsException 740 ("Coordinate out of bounds!"); 741 } 742 int pixels[]; 743 if (iArray != null) { 744 pixels = iArray; 745 } else { 746 pixels = new int [numBands]; 747 } 748 int pixelOffset = y*scanlineStride + x*pixelStride; 749 for (int i=0; i<numBands; i++) { 750 pixels[i] = data.getElem(bankIndices[i], 751 pixelOffset + bandOffsets[i]); 752 } 753 return pixels; 754 } 755 756 /** 757 * Returns all samples for the specified rectangle of pixels in 758 * an int array, one sample per array element. 759 * An <code>ArrayIndexOutOfBoundsException</code> might be thrown if 760 * the coordinates are not in bounds. 761 * @param x The X coordinate of the upper left pixel location 762 * @param y The Y coordinate of the upper left pixel location 763 * @param w The width of the pixel rectangle 764 * @param h The height of the pixel rectangle 765 * @param iArray If non-null, returns the samples in this array 766 * @param data The DataBuffer containing the image data 767 * @return the samples of the pixels within the specified region. 768 * @see #setPixels(int, int, int, int, int[], DataBuffer) 769 */ 770 public int[] getPixels(int x, int y, int w, int h, 771 int iArray[], DataBuffer data) { 772 int x1 = x + w; 773 int y1 = y + h; 774 775 if (x < 0 || x >= width || w > width || x1 < 0 || x1 > width || 776 y < 0 || y >= height || y > height || y1 < 0 || y1 > height) 777 { 778 throw new ArrayIndexOutOfBoundsException 779 ("Coordinate out of bounds!"); 780 } 781 int pixels[]; 782 if (iArray != null) { 783 pixels = iArray; 784 } else { 785 pixels = new int [w*h*numBands]; 786 } 787 int lineOffset = y*scanlineStride + x*pixelStride; 788 int srcOffset = 0; 789 790 for (int i = 0; i < h; i++) { 791 int pixelOffset = lineOffset; 792 for (int j = 0; j < w; j++) { 793 for (int k=0; k < numBands; k++) { 794 pixels[srcOffset++] = 795 data.getElem(bankIndices[k], pixelOffset + bandOffsets[k]); 796 } 797 pixelOffset += pixelStride; 798 } 799 lineOffset += scanlineStride; 800 } 801 return pixels; 802 } 803 804 /** 805 * Returns as int the sample in a specified band for the pixel 806 * located at (x,y). 807 * An <code>ArrayIndexOutOfBoundsException</code> might be thrown if 808 * the coordinates are not in bounds. 809 * @param x the X coordinate of the pixel location 810 * @param y the Y coordinate of the pixel location 811 * @param b the band to return 812 * @param data the <code>DataBuffer</code> containing the image data 813 * @return the sample in a specified band for the specified pixel 814 * @see #setSample(int, int, int, int, DataBuffer) 815 */ 816 public int getSample(int x, int y, int b, DataBuffer data) { 817 // Bounds check for 'b' will be performed automatically 818 if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) { 819 throw new ArrayIndexOutOfBoundsException 820 ("Coordinate out of bounds!"); 821 } 822 int sample = data.getElem(bankIndices[b], 823 y*scanlineStride + x*pixelStride + 824 bandOffsets[b]); 825 return sample; 826 } 827 828 /** 829 * Returns the sample in a specified band 830 * for the pixel located at (x,y) as a float. 831 * An <code>ArrayIndexOutOfBoundsException</code> might be 832 * thrown if the coordinates are not in bounds. 833 * @param x The X coordinate of the pixel location 834 * @param y The Y coordinate of the pixel location 835 * @param b The band to return 836 * @param data The DataBuffer containing the image data 837 * @return a float value representing the sample in the specified 838 * band for the specified pixel. 839 */ 840 public float getSampleFloat(int x, int y, int b, DataBuffer data) { 841 // Bounds check for 'b' will be performed automatically 842 if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) { 843 throw new ArrayIndexOutOfBoundsException 844 ("Coordinate out of bounds!"); 845 } 846 847 float sample = data.getElemFloat(bankIndices[b], 848 y*scanlineStride + x*pixelStride + 849 bandOffsets[b]); 850 return sample; 851 } 852 853 /** 854 * Returns the sample in a specified band 855 * for a pixel located at (x,y) as a double. 856 * An <code>ArrayIndexOutOfBoundsException</code> might be 857 * thrown if the coordinates are not in bounds. 858 * @param x The X coordinate of the pixel location 859 * @param y The Y coordinate of the pixel location 860 * @param b The band to return 861 * @param data The DataBuffer containing the image data 862 * @return a double value representing the sample in the specified 863 * band for the specified pixel. 864 */ 865 public double getSampleDouble(int x, int y, int b, DataBuffer data) { 866 // Bounds check for 'b' will be performed automatically 867 if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) { 868 throw new ArrayIndexOutOfBoundsException 869 ("Coordinate out of bounds!"); 870 } 871 872 double sample = data.getElemDouble(bankIndices[b], 873 y*scanlineStride + x*pixelStride + 874 bandOffsets[b]); 875 return sample; 876 } 877 878 /** 879 * Returns the samples in a specified band for the specified rectangle 880 * of pixels in an int array, one sample per data array element. 881 * An <code>ArrayIndexOutOfBoundsException</code> might be thrown if 882 * the coordinates are not in bounds. 883 * @param x The X coordinate of the upper left pixel location 884 * @param y The Y coordinate of the upper left pixel location 885 * @param w the width of the pixel rectangle 886 * @param h the height of the pixel rectangle 887 * @param b the band to return 888 * @param iArray if non-<code>null</code>, returns the samples 889 * in this array 890 * @param data the <code>DataBuffer</code> containing the image data 891 * @return the samples in the specified band of the specified pixel 892 * @see #setSamples(int, int, int, int, int, int[], DataBuffer) 893 */ 894 public int[] getSamples(int x, int y, int w, int h, int b, 895 int iArray[], DataBuffer data) { 896 // Bounds check for 'b' will be performed automatically 897 if ((x < 0) || (y < 0) || (x + w > width) || (y + h > height)) { 898 throw new ArrayIndexOutOfBoundsException 899 ("Coordinate out of bounds!"); 900 } 901 int samples[]; 902 if (iArray != null) { 903 samples = iArray; 904 } else { 905 samples = new int [w*h]; 906 } 907 int lineOffset = y*scanlineStride + x*pixelStride + bandOffsets[b]; 908 int srcOffset = 0; 909 910 for (int i = 0; i < h; i++) { 911 int sampleOffset = lineOffset; 912 for (int j = 0; j < w; j++) { 913 samples[srcOffset++] = data.getElem(bankIndices[b], 914 sampleOffset); 915 sampleOffset += pixelStride; 916 } 917 lineOffset += scanlineStride; 918 } 919 return samples; 920 } 921 922 /** 923 * Sets the data for a single pixel in the specified 924 * <code>DataBuffer</code> from a primitive array of type 925 * <code>TransferType</code>. For a <code>ComponentSampleModel</code>, 926 * this is the same as the data type, and samples are transferred 927 * one per array element. 928 * <p> 929 * The following code illustrates transferring data for one pixel from 930 * <code>DataBuffer</code> <code>db1</code>, whose storage layout is 931 * described by <code>ComponentSampleModel</code> <code>csm1</code>, 932 * to <code>DataBuffer</code> <code>db2</code>, whose storage layout 933 * is described by <code>ComponentSampleModel</code> <code>csm2</code>. 934 * The transfer is usually more efficient than using 935 * <code>getPixel</code> and <code>setPixel</code>. 936 * <pre> 937 * ComponentSampleModel csm1, csm2; 938 * DataBufferInt db1, db2; 939 * csm2.setDataElements(x, y, csm1.getDataElements(x, y, null, db1), 940 * db2); 941 * </pre> 942 * Using <code>getDataElements</code> and <code>setDataElements</code> 943 * to transfer between two <code>DataBuffer/SampleModel</code> pairs 944 * is legitimate if the <code>SampleModel</code> objects have 945 * the same number of bands, corresponding bands have the same number of 946 * bits per sample, and the <code>TransferType</code>s are the same. 947 * <p> 948 * A <code>ClassCastException</code> is thrown if <code>obj</code> is not 949 * a primitive array of type <code>TransferType</code>. 950 * An <code>ArrayIndexOutOfBoundsException</code> might be thrown if 951 * the coordinates are not in bounds, or if <code>obj</code> is not large 952 * enough to hold the pixel data. 953 * @param x the X coordinate of the pixel location 954 * @param y the Y coordinate of the pixel location 955 * @param obj a primitive array containing pixel data 956 * @param data the DataBuffer containing the image data 957 * @see #getDataElements(int, int, Object, DataBuffer) 958 */ 959 public void setDataElements(int x, int y, Object obj, DataBuffer data) { 960 if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) { 961 throw new ArrayIndexOutOfBoundsException 962 ("Coordinate out of bounds!"); 963 } 964 965 int type = getTransferType(); 966 int numDataElems = getNumDataElements(); 967 int pixelOffset = y*scanlineStride + x*pixelStride; 968 969 switch(type) { 970 971 case DataBuffer.TYPE_BYTE: 972 973 byte[] barray = (byte[])obj; 974 975 for (int i=0; i<numDataElems; i++) { 976 data.setElem(bankIndices[i], pixelOffset + bandOffsets[i], 977 ((int)barray[i])&0xff); 978 } 979 break; 980 981 case DataBuffer.TYPE_USHORT: 982 case DataBuffer.TYPE_SHORT: 983 984 short[] sarray = (short[])obj; 985 986 for (int i=0; i<numDataElems; i++) { 987 data.setElem(bankIndices[i], pixelOffset + bandOffsets[i], 988 ((int)sarray[i])&0xffff); 989 } 990 break; 991 992 case DataBuffer.TYPE_INT: 993 994 int[] iarray = (int[])obj; 995 996 for (int i=0; i<numDataElems; i++) { 997 data.setElem(bankIndices[i], 998 pixelOffset + bandOffsets[i], iarray[i]); 999 } 1000 break; 1001 1002 case DataBuffer.TYPE_FLOAT: 1003 1004 float[] farray = (float[])obj; 1005 1006 for (int i=0; i<numDataElems; i++) { 1007 data.setElemFloat(bankIndices[i], 1008 pixelOffset + bandOffsets[i], farray[i]); 1009 } 1010 break; 1011 1012 case DataBuffer.TYPE_DOUBLE: 1013 1014 double[] darray = (double[])obj; 1015 1016 for (int i=0; i<numDataElems; i++) { 1017 data.setElemDouble(bankIndices[i], 1018 pixelOffset + bandOffsets[i], darray[i]); 1019 } 1020 break; 1021 1022 } 1023 } 1024 1025 /** 1026 * Sets a pixel in the <code>DataBuffer</code> using an int array of 1027 * samples for input. An <code>ArrayIndexOutOfBoundsException</code> 1028 * might be thrown if the coordinates are 1029 * not in bounds. 1030 * @param x The X coordinate of the pixel location 1031 * @param y The Y coordinate of the pixel location 1032 * @param iArray The input samples in an int array 1033 * @param data The DataBuffer containing the image data 1034 * @see #getPixel(int, int, int[], DataBuffer) 1035 */ 1036 public void setPixel(int x, int y, int iArray[], DataBuffer data) { 1037 if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) { 1038 throw new ArrayIndexOutOfBoundsException 1039 ("Coordinate out of bounds!"); 1040 } 1041 int pixelOffset = y*scanlineStride + x*pixelStride; 1042 for (int i=0; i<numBands; i++) { 1043 data.setElem(bankIndices[i], 1044 pixelOffset + bandOffsets[i],iArray[i]); 1045 } 1046 } 1047 1048 /** 1049 * Sets all samples for a rectangle of pixels from an int array containing 1050 * one sample per array element. 1051 * An <code>ArrayIndexOutOfBoundsException</code> might be thrown if the 1052 * coordinates are not in bounds. 1053 * @param x The X coordinate of the upper left pixel location 1054 * @param y The Y coordinate of the upper left pixel location 1055 * @param w The width of the pixel rectangle 1056 * @param h The height of the pixel rectangle 1057 * @param iArray The input samples in an int array 1058 * @param data The DataBuffer containing the image data 1059 * @see #getPixels(int, int, int, int, int[], DataBuffer) 1060 */ 1061 public void setPixels(int x, int y, int w, int h, 1062 int iArray[], DataBuffer data) { 1063 int x1 = x + w; 1064 int y1 = y + h; 1065 1066 if (x < 0 || x >= width || w > width || x1 < 0 || x1 > width || 1067 y < 0 || y >= height || h > height || y1 < 0 || y1 > height) 1068 { 1069 throw new ArrayIndexOutOfBoundsException 1070 ("Coordinate out of bounds!"); 1071 } 1072 1073 int lineOffset = y*scanlineStride + x*pixelStride; 1074 int srcOffset = 0; 1075 1076 for (int i = 0; i < h; i++) { 1077 int pixelOffset = lineOffset; 1078 for (int j = 0; j < w; j++) { 1079 for (int k=0; k < numBands; k++) { 1080 data.setElem(bankIndices[k], pixelOffset + bandOffsets[k], 1081 iArray[srcOffset++]); 1082 } 1083 pixelOffset += pixelStride; 1084 } 1085 lineOffset += scanlineStride; 1086 } 1087 } 1088 1089 /** 1090 * Sets a sample in the specified band for the pixel located at (x,y) 1091 * in the <code>DataBuffer</code> using an int for input. 1092 * An <code>ArrayIndexOutOfBoundsException</code> might be thrown if the 1093 * coordinates are not in bounds. 1094 * @param x The X coordinate of the pixel location 1095 * @param y The Y coordinate of the pixel location 1096 * @param b the band to set 1097 * @param s the input sample as an int 1098 * @param data the DataBuffer containing the image data 1099 * @see #getSample(int, int, int, DataBuffer) 1100 */ 1101 public void setSample(int x, int y, int b, int s, 1102 DataBuffer data) { 1103 // Bounds check for 'b' will be performed automatically 1104 if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) { 1105 throw new ArrayIndexOutOfBoundsException 1106 ("Coordinate out of bounds!"); 1107 } 1108 data.setElem(bankIndices[b], 1109 y*scanlineStride + x*pixelStride + bandOffsets[b], s); 1110 } 1111 1112 /** 1113 * Sets a sample in the specified band for the pixel located at (x,y) 1114 * in the <code>DataBuffer</code> using a float for input. 1115 * An <code>ArrayIndexOutOfBoundsException</code> might be thrown if 1116 * the coordinates are not in bounds. 1117 * @param x The X coordinate of the pixel location 1118 * @param y The Y coordinate of the pixel location 1119 * @param b The band to set 1120 * @param s The input sample as a float 1121 * @param data The DataBuffer containing the image data 1122 * @see #getSample(int, int, int, DataBuffer) 1123 */ 1124 public void setSample(int x, int y, int b, 1125 float s , 1126 DataBuffer data) { 1127 // Bounds check for 'b' will be performed automatically 1128 if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) { 1129 throw new ArrayIndexOutOfBoundsException 1130 ("Coordinate out of bounds!"); 1131 } 1132 data.setElemFloat(bankIndices[b], 1133 y*scanlineStride + x*pixelStride + bandOffsets[b], 1134 s); 1135 } 1136 1137 /** 1138 * Sets a sample in the specified band for the pixel located at (x,y) 1139 * in the <code>DataBuffer</code> using a double for input. 1140 * An <code>ArrayIndexOutOfBoundsException</code> might be thrown if 1141 * the coordinates are not in bounds. 1142 * @param x The X coordinate of the pixel location 1143 * @param y The Y coordinate of the pixel location 1144 * @param b The band to set 1145 * @param s The input sample as a double 1146 * @param data The DataBuffer containing the image data 1147 * @see #getSample(int, int, int, DataBuffer) 1148 */ 1149 public void setSample(int x, int y, int b, 1150 double s, 1151 DataBuffer data) { 1152 // Bounds check for 'b' will be performed automatically 1153 if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) { 1154 throw new ArrayIndexOutOfBoundsException 1155 ("Coordinate out of bounds!"); 1156 } 1157 data.setElemDouble(bankIndices[b], 1158 y*scanlineStride + x*pixelStride + bandOffsets[b], 1159 s); 1160 } 1161 1162 /** 1163 * Sets the samples in the specified band for the specified rectangle 1164 * of pixels from an int array containing one sample per data array element. 1165 * An <code>ArrayIndexOutOfBoundsException</code> might be thrown if the 1166 * coordinates are not in bounds. 1167 * @param x The X coordinate of the upper left pixel location 1168 * @param y The Y coordinate of the upper left pixel location 1169 * @param w The width of the pixel rectangle 1170 * @param h The height of the pixel rectangle 1171 * @param b The band to set 1172 * @param iArray The input samples in an int array 1173 * @param data The DataBuffer containing the image data 1174 * @see #getSamples(int, int, int, int, int, int[], DataBuffer) 1175 */ 1176 public void setSamples(int x, int y, int w, int h, int b, 1177 int iArray[], DataBuffer data) { 1178 // Bounds check for 'b' will be performed automatically 1179 if ((x < 0) || (y < 0) || (x + w > width) || (y + h > height)) { 1180 throw new ArrayIndexOutOfBoundsException 1181 ("Coordinate out of bounds!"); 1182 } 1183 int lineOffset = y*scanlineStride + x*pixelStride + bandOffsets[b]; 1184 int srcOffset = 0; 1185 1186 for (int i = 0; i < h; i++) { 1187 int sampleOffset = lineOffset; 1188 for (int j = 0; j < w; j++) { 1189 data.setElem(bankIndices[b], sampleOffset, iArray[srcOffset++]); 1190 sampleOffset += pixelStride; 1191 } 1192 lineOffset += scanlineStride; 1193 } 1194 } 1195 1196 public boolean equals(Object o) { 1197 if ((o == null) || !(o instanceof ComponentSampleModel)) { 1198 return false; 1199 } 1200 1201 ComponentSampleModel that = (ComponentSampleModel)o; 1202 return this.width == that.width && 1203 this.height == that.height && 1204 this.numBands == that.numBands && 1205 this.dataType == that.dataType && 1206 Arrays.equals(this.bandOffsets, that.bandOffsets) && 1207 Arrays.equals(this.bankIndices, that.bankIndices) && 1208 this.numBands == that.numBands && 1209 this.numBanks == that.numBanks && 1210 this.scanlineStride == that.scanlineStride && 1211 this.pixelStride == that.pixelStride; 1212 } 1213 1214 // If we implement equals() we must also implement hashCode 1215 public int hashCode() { 1216 int hash = 0; 1217 hash = width; 1218 hash <<= 8; 1219 hash ^= height; 1220 hash <<= 8; 1221 hash ^= numBands; 1222 hash <<= 8; 1223 hash ^= dataType; 1224 hash <<= 8; 1225 for (int i = 0; i < bandOffsets.length; i++) { 1226 hash ^= bandOffsets[i]; 1227 hash <<= 8; 1228 } 1229 for (int i = 0; i < bankIndices.length; i++) { 1230 hash ^= bankIndices[i]; 1231 hash <<= 8; 1232 } 1233 hash ^= numBands; 1234 hash <<= 8; 1235 hash ^= numBanks; 1236 hash <<= 8; 1237 hash ^= scanlineStride; 1238 hash <<= 8; 1239 hash ^= pixelStride; 1240 return hash; 1241 } 1242 }