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