Frames | No Frames |
1: /* Copyright (C) 2000, 2002, 2006, Free Software Foundation 2: 3: This file is part of GNU Classpath. 4: 5: GNU Classpath is free software; you can redistribute it and/or modify 6: it under the terms of the GNU General Public License as published by 7: the Free Software Foundation; either version 2, or (at your option) 8: any later version. 9: 10: GNU Classpath is distributed in the hope that it will be useful, but 11: WITHOUT ANY WARRANTY; without even the implied warranty of 12: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13: General Public License for more details. 14: 15: You should have received a copy of the GNU General Public License 16: along with GNU Classpath; see the file COPYING. If not, write to the 17: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 18: 02110-1301 USA. 19: 20: Linking this library statically or dynamically with other modules is 21: making a combined work based on this library. Thus, the terms and 22: conditions of the GNU General Public License cover the whole 23: combination. 24: 25: As a special exception, the copyright holders of this library give you 26: permission to link this library with independent modules to produce an 27: executable, regardless of the license terms of these independent 28: modules, and to copy and distribute the resulting executable under 29: terms of your choice, provided that you also meet, for each linked 30: independent module, the terms and conditions of the license of that 31: module. An independent module is a module which is not derived from 32: or based on this library. If you modify this library, you may extend 33: this exception to your version of the library, but you are not 34: obligated to do so. If you do not wish to do so, delete this 35: exception statement from your version. */ 36: 37: package java.awt.image; 38: 39: import gnu.java.awt.Buffers; 40: 41: import java.util.Arrays; 42: 43: /* FIXME: This class does not yet support data type TYPE_SHORT */ 44: 45: /** 46: * ComponentSampleModel supports a flexible organization of pixel samples in 47: * memory, permitting pixel samples to be interleaved by band, by scanline, 48: * and by pixel. 49: * 50: * A DataBuffer for this sample model has K banks of data. Pixels have N 51: * samples, so there are N bands in the DataBuffer. Each band is completely 52: * contained in one bank of data, but a bank may contain more than one band. 53: * Each pixel sample is stored in a single data element. 54: * 55: * Within a bank, each band begins at an offset stored in bandOffsets. The 56: * banks containing the band is given by bankIndices. Within the bank, there 57: * are three dimensions - band, pixel, and scanline. The dimension ordering 58: * is controlled by bandOffset, pixelStride, and scanlineStride, which means 59: * that any combination of interleavings is supported. 60: * 61: * @author Rolf W. Rasmussen (rolfwr@ii.uib.no) 62: */ 63: public class ComponentSampleModel extends SampleModel 64: { 65: /** The offsets to the first sample for each band. */ 66: protected int[] bandOffsets; 67: 68: /** The indices of the bank used to store each band in a data buffer. */ 69: protected int[] bankIndices; 70: 71: /** 72: * The number of bands in the image. 73: * @specnote This field shadows the protected numBands in SampleModel. 74: */ 75: protected int numBands; 76: 77: /** Used when creating data buffers. */ 78: protected int numBanks; 79: 80: /** 81: * The number of data elements between a sample in one row and the 82: * corresponding sample in the next row. 83: */ 84: protected int scanlineStride; 85: 86: /** 87: * The number of data elements between a sample for one pixel and the 88: * corresponding sample for the next pixel in the same row. 89: */ 90: protected int pixelStride; 91: 92: private boolean tightPixelPacking = false; 93: 94: /** 95: * Creates a new sample model that assumes that all bands are stored in a 96: * single bank of the {@link DataBuffer}. 97: * <p> 98: * Note that the <code>bandOffsets</code> array is copied to internal storage 99: * to prevent subsequent changes to the array from affecting this object. 100: * 101: * @param dataType the data type (one of {@link DataBuffer#TYPE_BYTE}, 102: * {@link DataBuffer#TYPE_USHORT}, {@link DataBuffer#TYPE_SHORT}, 103: * {@link DataBuffer#TYPE_INT}, {@link DataBuffer#TYPE_FLOAT} or 104: * {@link DataBuffer#TYPE_DOUBLE}). 105: * @param w the width in pixels. 106: * @param h the height in pixels. 107: * @param pixelStride the number of data elements in the step from a sample 108: * in one pixel to the corresponding sample in the next pixel. 109: * @param scanlineStride the number of data elements in the step from a 110: * sample in a pixel to the corresponding sample in the pixel in the next 111: * row. 112: * @param bandOffsets the offset to the first element for each band, with 113: * the size of the array defining the number of bands (<code>null</code> 114: * not permitted). 115: * 116: * @throws IllegalArgumentException if <code>dataType</code> is not one of 117: * the specified values. 118: * @throws IllegalArgumentException if <code>w</code> is less than or equal 119: * to zero. 120: * @throws IllegalArgumentException if <code>h</code> is less than or equal 121: * to zero. 122: * @throws IllegalArgumentException if <code>w * h</code> exceeds 123: * {@link Integer#MAX_VALUE}. 124: * @throws IllegalArgumentException if <code>pixelStride</code> is negative. 125: * @throws IllegalArgumentException if <code>scanlineStride</code> is less 126: * than or equal to zero. 127: * @throws IllegalArgumentException if <code>bandOffsets</code> has zero 128: * length. 129: */ 130: public ComponentSampleModel(int dataType, 131: int w, int h, 132: int pixelStride, 133: int scanlineStride, 134: int[] bandOffsets) 135: { 136: this(dataType, w, h, pixelStride, scanlineStride, 137: new int[bandOffsets.length], bandOffsets); 138: } 139: 140: /** 141: * Creates a new sample model that assumes that all bands are stored in a 142: * single bank of the {@link DataBuffer}. 143: * 144: * @param dataType the data type (one of {@link DataBuffer#TYPE_BYTE}, 145: * {@link DataBuffer#TYPE_USHORT}, {@link DataBuffer#TYPE_SHORT}, 146: * {@link DataBuffer#TYPE_INT}, {@link DataBuffer#TYPE_FLOAT} or 147: * {@link DataBuffer#TYPE_DOUBLE}). 148: * @param w the width in pixels. 149: * @param h the height in pixels. 150: * @param pixelStride the number of data elements in the step from a sample 151: * in one pixel to the corresponding sample in the next pixel. 152: * @param scanlineStride the number of data elements in the step from a 153: * sample in a pixel to the corresponding sample in the pixel in the next 154: * row. 155: * @param bankIndices the index of the bank in which each band is stored 156: * (<code>null</code> not permitted). This array is copied to internal 157: * storage so that subsequent updates to the array do not affect the sample 158: * model. 159: * @param bandOffsets the offset to the first element for each band, with 160: * the size of the array defining the number of bands (<code>null</code> 161: * not permitted). This array is copied to internal storage so that 162: * subsequent updates to the array do not affect the sample model. 163: * 164: * @throws IllegalArgumentException if <code>dataType</code> is not one of 165: * the specified values. 166: * @throws IllegalArgumentException if <code>w</code> is less than or equal 167: * to zero. 168: * @throws IllegalArgumentException if <code>h</code> is less than or equal 169: * to zero. 170: * @throws IllegalArgumentException if <code>w * h</code> exceeds 171: * {@link Integer#MAX_VALUE}. 172: * @throws IllegalArgumentException if <code>pixelStride</code> is negative. 173: * @throws IllegalArgumentException if <code>scanlineStride</code> is less 174: * than or equal to zero. 175: * @throws IllegalArgumentException if <code>bandOffsets</code> has zero 176: * length. 177: */ 178: public ComponentSampleModel(int dataType, 179: int w, int h, 180: int pixelStride, 181: int scanlineStride, 182: int[] bankIndices, 183: int[] bandOffsets) 184: { 185: super(dataType, w, h, bandOffsets.length); 186: 187: // super permits DataBuffer.TYPE_UNDEFINED but this class doesn't... 188: if (dataType == DataBuffer.TYPE_UNDEFINED) 189: throw new IllegalArgumentException("Unsupported dataType."); 190: 191: if ((pixelStride < 0) || (scanlineStride < 0) || (bandOffsets.length < 1) 192: || (bandOffsets.length != bankIndices.length)) 193: throw new IllegalArgumentException(); 194: 195: this.bandOffsets = (int[]) bandOffsets.clone(); 196: this.bankIndices = (int[]) bankIndices.clone(); 197: this.numBands = bandOffsets.length; 198: 199: this.numBanks = 0; 200: for (int b = 0; b < bankIndices.length; b++) 201: this.numBanks = Math.max(this.numBanks, bankIndices[b] + 1); 202: 203: this.scanlineStride = scanlineStride; 204: this.pixelStride = pixelStride; 205: 206: // See if we can use some speedups 207: 208: /* FIXME: May these checks should be reserved for the 209: PixelInterleavedSampleModel? */ 210: 211: if (pixelStride == numBands) 212: { 213: tightPixelPacking = true; 214: for (int b = 0; b < numBands; b++) { 215: if ((bandOffsets[b] != b) || (bankIndices[b] != 0)) 216: { 217: tightPixelPacking = false; 218: break; 219: } 220: } 221: } 222: } 223: 224: /** 225: * Creates a new sample model that is compatible with this one, but with the 226: * specified dimensions. 227: * 228: * @param w the width (must be greater than zero). 229: * @param h the height (must be greater than zero). 230: * 231: * @return A new sample model. 232: */ 233: public SampleModel createCompatibleSampleModel(int w, int h) 234: { 235: return new ComponentSampleModel(dataType, w, h, pixelStride, 236: scanlineStride, bankIndices, 237: bandOffsets); 238: } 239: 240: /** 241: * Creates a new sample model that provides access to a subset of the bands 242: * that this sample model supports. 243: * 244: * @param bands the bands (<code>null</code> not permitted). 245: * 246: * @return The new sample model. 247: */ 248: public SampleModel createSubsetSampleModel(int[] bands) 249: { 250: int numBands = bands.length; 251: 252: int[] bankIndices = new int[numBands]; 253: int[] bandOffsets = new int[numBands]; 254: for (int b = 0; b < numBands; b++) 255: { 256: bankIndices[b] = this.bankIndices[bands[b]]; 257: bandOffsets[b] = this.bandOffsets[bands[b]]; 258: } 259: 260: return new ComponentSampleModel(dataType, width, height, pixelStride, 261: scanlineStride, bankIndices, 262: bandOffsets); 263: } 264: 265: /** 266: * Creates a new data buffer that is compatible with this sample model. 267: * 268: * @return The new data buffer. 269: */ 270: public DataBuffer createDataBuffer() 271: { 272: // Maybe this value should be precalculated in the constructor? 273: int highestOffset = 0; 274: for (int b = 0; b < numBands; b++) 275: highestOffset = Math.max(highestOffset, bandOffsets[b]); 276: int size = pixelStride * (width - 1) + scanlineStride * (height - 1) 277: + highestOffset + 1; 278: 279: return Buffers.createBuffer(getDataType(), size, numBanks); 280: } 281: 282: /** 283: * Returns the offset of the sample in band 0 for the pixel at location 284: * <code>(x, y)</code>. This offset can be used to read a sample value from 285: * a {@link DataBuffer}. 286: * 287: * @param x the x-coordinate. 288: * @param y the y-coordinate. 289: * 290: * @return The offset. 291: * 292: * @see #getOffset(int, int, int) 293: */ 294: public int getOffset(int x, int y) 295: { 296: return getOffset(x, y, 0); 297: } 298: 299: /** 300: * Returns the offset of the sample in band <code>b</code> for the pixel at 301: * location <code>(x, y)</code>. This offset can be used to read a sample 302: * value from a {@link DataBuffer}. 303: * 304: * @param x the x-coordinate. 305: * @param y the y-coordinate. 306: * @param b the band index. 307: * 308: * @return The offset. 309: */ 310: public int getOffset(int x, int y, int b) 311: { 312: return bandOffsets[b] + pixelStride * x + scanlineStride * y; 313: } 314: 315: /** 316: * Returns the size in bits for each sample (one per band). For this sample 317: * model, each band has the same sample size and this is determined by the 318: * data type for the sample model. 319: * 320: * @return The sample sizes. 321: * 322: * @see SampleModel#getDataType() 323: */ 324: public final int[] getSampleSize() 325: { 326: int size = DataBuffer.getDataTypeSize(getDataType()); 327: int[] sizes = new int[numBands]; 328: 329: java.util.Arrays.fill(sizes, size); 330: return sizes; 331: } 332: 333: /** 334: * Returns the size in bits for the samples in the specified band. In this 335: * class, the sample size is the same for every band and is determined from 336: * the data type for the model. 337: * 338: * @param band the band index (ignored here). 339: * 340: * @return The sample size in bits. 341: * 342: * @see SampleModel#getDataType() 343: */ 344: public final int getSampleSize(int band) 345: { 346: return DataBuffer.getDataTypeSize(getDataType()); 347: } 348: 349: /** 350: * Returns the indices of the bank(s) in the {@link DataBuffer} used to 351: * store the samples for each band. The returned array is a copy, so that 352: * altering it will not impact the sample model. 353: * 354: * @return The bank indices. 355: */ 356: public final int[] getBankIndices() 357: { 358: return (int[]) bankIndices.clone(); 359: } 360: 361: /** 362: * Returns the offsets to the first sample in each band. The returned array 363: * is a copy, so that altering it will not impact the sample model. 364: * 365: * @return The offsets. 366: */ 367: public final int[] getBandOffsets() 368: { 369: return (int[]) bandOffsets.clone(); 370: } 371: 372: /** 373: * Returns the distance (in terms of element indices) between the sample for 374: * one pixel and the corresponding sample for the equivalent pixel in the 375: * next row. This is used in the calculation of the element offset for 376: * retrieving samples from a {@link DataBuffer}. 377: * 378: * @return The distance between pixel samples in consecutive rows. 379: */ 380: public final int getScanlineStride() 381: { 382: return scanlineStride; 383: } 384: 385: /** 386: * Returns the distance (in terms of element indices) between the sample for 387: * one pixel and the corresponding sample for the next pixel in a row. This 388: * is used in the calculation of the element offset for retrieving samples 389: * from a {@link DataBuffer}. 390: * 391: * @return The distance between pixel samples in the same row. 392: */ 393: public final int getPixelStride() 394: { 395: return pixelStride; 396: } 397: 398: /** 399: * Returns the number of data elements used to store the samples for one 400: * pixel. In this model, this is the same as the number of bands. 401: * 402: * @return The number of data elements used to store the samples for one 403: * pixel. 404: */ 405: public final int getNumDataElements() 406: { 407: return numBands; 408: } 409: 410: /** 411: * Returns the samples for the pixel at location <code>(x, y)</code> in 412: * a primitive array (the array type is determined by the data type for 413: * this model). The <code>obj</code> argument provides an option to supply 414: * an existing array to hold the result, if this is <code>null</code> a new 415: * array will be allocated. 416: * 417: * @param x the x-coordinate. 418: * @param y the y-coordinate. 419: * @param obj a primitive array that, if not <code>null</code>, will be 420: * used to store and return the sample values. 421: * @param data the data buffer (<code>null</code> not permitted). 422: * 423: * @return An array of sample values for the specified pixel. 424: */ 425: public Object getDataElements(int x, int y, Object obj, DataBuffer data) 426: { 427: int xyOffset = pixelStride * x + scanlineStride * y; 428: 429: int[] totalBandDataOffsets = new int[numBands]; 430: 431: /* Notice that band and bank offsets are different. Band offsets 432: are managed by the sample model, and bank offsets are managed 433: by the data buffer. Both must be accounted for. */ 434: 435: /* FIXME: For single pixels, it is probably easier to simple 436: call getElem instead of calculating the bank offset ourself. 437: 438: On the other hand, then we need to push the value through 439: the int type returned by the getElem method. */ 440: 441: int[] bankOffsets = data.getOffsets(); 442: 443: for (int b = 0; b < numBands; b++) 444: { 445: totalBandDataOffsets[b] = bandOffsets[b] + bankOffsets[bankIndices[b]] 446: + xyOffset; 447: } 448: 449: try 450: { 451: switch (getTransferType()) 452: { 453: case DataBuffer.TYPE_BYTE: 454: DataBufferByte inByte = (DataBufferByte) data; 455: byte[] outByte = (byte[]) obj; 456: if (outByte == null) 457: outByte = new byte[numBands]; 458: 459: for (int b = 0; b < numBands; b++) 460: { 461: int dOffset = totalBandDataOffsets[b]; 462: outByte[b] = inByte.getData(bankIndices[b])[dOffset]; 463: } 464: return outByte; 465: 466: case DataBuffer.TYPE_USHORT: 467: DataBufferUShort inUShort = (DataBufferUShort) data; 468: short[] outUShort = (short[]) obj; 469: if (outUShort == null) 470: outUShort = new short[numBands]; 471: 472: for (int b = 0; b < numBands; b++) 473: { 474: int dOffset = totalBandDataOffsets[b]; 475: outUShort[b] = inUShort.getData(bankIndices[b])[dOffset]; 476: } 477: return outUShort; 478: 479: case DataBuffer.TYPE_SHORT: 480: DataBufferShort inShort = (DataBufferShort) data; 481: short[] outShort = (short[]) obj; 482: if (outShort == null) 483: outShort = new short[numBands]; 484: 485: for (int b = 0; b < numBands; b++) 486: { 487: int dOffset = totalBandDataOffsets[b]; 488: outShort[b] = inShort.getData(bankIndices[b])[dOffset]; 489: } 490: return outShort; 491: 492: case DataBuffer.TYPE_INT: 493: DataBufferInt inInt = (DataBufferInt) data; 494: int[] outInt = (int[]) obj; 495: if (outInt == null) 496: outInt = new int[numBands]; 497: 498: for (int b = 0; b < numBands; b++) 499: { 500: int dOffset = totalBandDataOffsets[b]; 501: outInt[b] = inInt.getData(bankIndices[b])[dOffset]; 502: } 503: return outInt; 504: 505: case DataBuffer.TYPE_FLOAT: 506: DataBufferFloat inFloat = (DataBufferFloat) data; 507: float[] outFloat = (float[]) obj; 508: if (outFloat == null) 509: outFloat = new float[numBands]; 510: 511: for (int b = 0; b < numBands; b++) 512: { 513: int dOffset = totalBandDataOffsets[b]; 514: outFloat[b] = inFloat.getData(bankIndices[b])[dOffset]; 515: } 516: return outFloat; 517: 518: case DataBuffer.TYPE_DOUBLE: 519: DataBufferDouble inDouble = (DataBufferDouble) data; 520: double[] outDouble = (double[]) obj; 521: if (outDouble == null) 522: outDouble = new double[numBands]; 523: 524: for (int b = 0; b < numBands; b++) 525: { 526: int dOffset = totalBandDataOffsets[b]; 527: outDouble[b] = inDouble.getData(bankIndices[b])[dOffset]; 528: } 529: return outDouble; 530: 531: default: 532: throw new IllegalStateException("unknown transfer type " 533: + getTransferType()); 534: } 535: } 536: catch (ArrayIndexOutOfBoundsException aioobe) 537: { 538: String msg = "While reading data elements, " + 539: "x=" + x + ", y=" + y +", " + ", xyOffset=" + xyOffset + 540: ", data.getSize()=" + data.getSize() + ": " + aioobe; 541: throw new ArrayIndexOutOfBoundsException(msg); 542: } 543: } 544: 545: /** 546: * Returns the samples for the pixels in the region defined by 547: * <code>(x, y, w, h)</code> in a primitive array (the array type is 548: * determined by the data type for this model). The <code>obj</code> 549: * argument provides an option to supply an existing array to hold the 550: * result, if this is <code>null</code> a new array will be allocated. 551: * 552: * @param x the x-coordinate. 553: * @param y the y-coordinate. 554: * @param w the width. 555: * @param h the height. 556: * @param obj a primitive array that, if not <code>null</code>, will be 557: * used to store and return the sample values. 558: * @param data the data buffer (<code>null</code> not permitted). 559: * 560: * @return An array of sample values for the specified pixels. 561: * 562: * @see #setDataElements(int, int, int, int, Object, DataBuffer) 563: */ 564: public Object getDataElements(int x, int y, int w, int h, Object obj, 565: DataBuffer data) 566: { 567: if (!tightPixelPacking) 568: { 569: return super.getDataElements(x, y, w, h, obj, data); 570: } 571: 572: // using get speedup 573: 574: // We can copy whole rows 575: int rowSize = w * numBands; 576: int dataSize = rowSize * h; 577: 578: DataBuffer transferBuffer = Buffers.createBuffer(getTransferType(), obj, 579: dataSize); 580: obj = Buffers.getData(transferBuffer); 581: 582: int inOffset = pixelStride * x + scanlineStride * y + data.getOffset(); 583: // Assumes only one band is used 584: 585: /* We don't add band offsets since we assume that bands have 586: offsets 0, 1, 2, ... */ 587: 588: // See if we can copy everything in one go 589: if (scanlineStride == rowSize) 590: { 591: // Collapse scan lines: 592: rowSize *= h; 593: // We ignore scanlineStride since it won't be of any use 594: h = 1; 595: } 596: 597: int outOffset = 0; 598: Object inArray = Buffers.getData(data); 599: for (int yd = 0; yd < h; yd++) 600: { 601: System.arraycopy(inArray, inOffset, obj, outOffset, rowSize); 602: inOffset += scanlineStride; 603: outOffset += rowSize; 604: } 605: return obj; 606: } 607: 608: /** 609: * Sets the samples for the pixels in the region defined by 610: * <code>(x, y, w, h)</code> from a supplied primitive array (the array type 611: * must be consistent with the data type for this model). 612: * 613: * @param x the x-coordinate. 614: * @param y the y-coordinate. 615: * @param w the width. 616: * @param h the height. 617: * @param obj a primitive array containing the sample values. 618: * @param data the data buffer (<code>null</code> not permitted). 619: * 620: * @see #getDataElements(int, int, int, int, Object, DataBuffer) 621: */ 622: public void setDataElements(int x, int y, int w, int h, 623: Object obj, DataBuffer data) 624: { 625: if (!tightPixelPacking) 626: { 627: super.setDataElements(x, y, w, h, obj, data); 628: return; 629: } 630: 631: // using set speedup, we can copy whole rows 632: int rowSize = w * numBands; 633: int dataSize = rowSize * h; 634: 635: DataBuffer transferBuffer 636: = Buffers.createBufferFromData(getTransferType(), obj, dataSize); 637: 638: int[] bankOffsets = data.getOffsets(); 639: 640: int outOffset = pixelStride * x + scanlineStride * y + bankOffsets[0]; 641: // same assumptions as in get... 642: 643: // See if we can copy everything in one go 644: if (scanlineStride == rowSize) 645: { 646: // Collapse scan lines: 647: rowSize *= h; 648: h = 1; 649: } 650: 651: int inOffset = 0; 652: Object outArray = Buffers.getData(data); 653: for (int yd = 0; yd < h; yd++) 654: { 655: System.arraycopy(obj, inOffset, outArray, outOffset, rowSize); 656: outOffset += scanlineStride; 657: inOffset += rowSize; 658: } 659: } 660: 661: /** 662: * Returns all the samples for the pixel at location <code>(x, y)</code> 663: * stored in the specified data buffer. 664: * 665: * @param x the x-coordinate. 666: * @param y the y-coordinate. 667: * @param iArray an array that will be populated with the sample values and 668: * returned as the result. The size of this array should be equal to the 669: * number of bands in the model. If the array is <code>null</code>, a new 670: * array is created. 671: * @param data the data buffer (<code>null</code> not permitted). 672: * 673: * @return The samples for the specified pixel. 674: * 675: * @see #setPixel(int, int, int[], DataBuffer) 676: */ 677: public int[] getPixel(int x, int y, int[] iArray, DataBuffer data) 678: { 679: if (x < 0 || x >= width || y < 0 || y >= height) 680: throw new ArrayIndexOutOfBoundsException("Pixel (" + x + ", " + y 681: + ") is out of bounds."); 682: int offset = pixelStride * x + scanlineStride * y; 683: if (iArray == null) 684: iArray = new int[numBands]; 685: for (int b = 0; b < numBands; b++) 686: { 687: iArray[b] = data.getElem(bankIndices[b], offset + bandOffsets[b]); 688: } 689: return iArray; 690: } 691: 692: /** 693: * Returns the samples for all the pixels in a rectangular region. 694: * 695: * @param x the x-coordinate. 696: * @param y the y-coordinate. 697: * @param w the width. 698: * @param h the height. 699: * @param iArray an array that if non-<code>null</code> will be populated 700: * with the sample values and returned as the result. 701: * @param data the data buffer (<code>null</code> not permitted). 702: * 703: * @return The samples for all the pixels in the rectangle. 704: */ 705: public int[] getPixels(int x, int y, int w, int h, int[] iArray, 706: DataBuffer data) 707: { 708: int offset = pixelStride * x + scanlineStride * y; 709: if (iArray == null) 710: iArray = new int[numBands * w * h]; 711: int outOffset = 0; 712: for (y = 0; y < h; y++) 713: { 714: int lineOffset = offset; 715: for (x = 0; x < w; x++) 716: { 717: for (int b = 0; b < numBands; b++) 718: { 719: iArray[outOffset++] 720: = data.getElem(bankIndices[b], lineOffset+bandOffsets[b]); 721: } 722: lineOffset += pixelStride; 723: } 724: offset += scanlineStride; 725: } 726: return iArray; 727: } 728: 729: /** 730: * Returns the sample for band <code>b</code> of the pixel at 731: * <code>(x, y)</code> that is stored in the specified data buffer. 732: * 733: * @param x the x-coordinate. 734: * @param y the y-coordinate. 735: * @param b the band index. 736: * @param data the data buffer (<code>null</code> not permitted). 737: * 738: * @return The sample value. 739: * 740: * @throws ArrayIndexOutOfBoundsException if <code>(x, y)</code> is outside 741: * the bounds <code>[0, 0, width, height]</code>. 742: * 743: * @see #setSample(int, int, int, int, DataBuffer) 744: */ 745: public int getSample(int x, int y, int b, DataBuffer data) 746: { 747: if (x < 0 || x >= width || y < 0 || y >= height) 748: throw new ArrayIndexOutOfBoundsException("Sample (" + x + ", " + y 749: + ") is out of bounds."); 750: return data.getElem(bankIndices[b], getOffset(x, y, b)); 751: } 752: 753: /** 754: * Sets the samples for the pixel at location <code>(x, y)</code> from the 755: * supplied primitive array (the array type must be consistent with the data 756: * type for this model). 757: * 758: * @param x the x-coordinate. 759: * @param y the y-coordinate. 760: * @param obj a primitive array containing the pixel's sample values. 761: * @param data the data buffer (<code>null</code> not permitted). 762: * 763: * @see #setDataElements(int, int, Object, DataBuffer) 764: */ 765: public void setDataElements(int x, int y, Object obj, DataBuffer data) 766: { 767: int offset = pixelStride * x + scanlineStride * y; 768: int[] totalBandDataOffsets = new int[numBands]; 769: int[] bankOffsets = data.getOffsets(); 770: for (int b = 0; b < numBands; b++) 771: totalBandDataOffsets[b] = bandOffsets[b] + bankOffsets[bankIndices[b]] 772: + offset; 773: 774: switch (getTransferType()) 775: { 776: case DataBuffer.TYPE_BYTE: 777: { 778: DataBufferByte out = (DataBufferByte) data; 779: byte[] in = (byte[]) obj; 780: 781: for (int b = 0; b < numBands; b++) 782: out.getData(bankIndices[b])[totalBandDataOffsets[b]] = in[b]; 783: 784: return; 785: } 786: case DataBuffer.TYPE_USHORT: 787: { 788: DataBufferUShort out = (DataBufferUShort) data; 789: short[] in = (short[]) obj; 790: 791: for (int b = 0; b < numBands; b++) 792: out.getData(bankIndices[b])[totalBandDataOffsets[b]] = in[b]; 793: 794: return; 795: } 796: case DataBuffer.TYPE_SHORT: 797: { 798: DataBufferShort out = (DataBufferShort) data; 799: short[] in = (short[]) obj; 800: 801: for (int b = 0; b < numBands; b++) 802: out.getData(bankIndices[b])[totalBandDataOffsets[b]] = in[b]; 803: 804: return; 805: } 806: case DataBuffer.TYPE_INT: 807: { 808: DataBufferInt out = (DataBufferInt) data; 809: int[] in = (int[]) obj; 810: 811: for (int b = 0; b < numBands; b++) 812: out.getData(bankIndices[b])[totalBandDataOffsets[b]] = in[b]; 813: 814: return; 815: } 816: case DataBuffer.TYPE_FLOAT: 817: { 818: DataBufferFloat out = (DataBufferFloat) data; 819: float[] in = (float[]) obj; 820: 821: for (int b = 0; b < numBands; b++) 822: out.getData(bankIndices[b])[totalBandDataOffsets[b]] = in[b]; 823: 824: return; 825: } 826: case DataBuffer.TYPE_DOUBLE: 827: { 828: DataBufferDouble out = (DataBufferDouble) data; 829: double[] in = (double[]) obj; 830: 831: for (int b = 0; b < numBands; b++) 832: out.getData(bankIndices[b])[totalBandDataOffsets[b]] = in[b]; 833: 834: return; 835: } 836: default: 837: throw new UnsupportedOperationException("transfer type not " + 838: "implemented"); 839: } 840: } 841: 842: /** 843: * Sets the sample values for the pixel at location <code>(x, y)</code> 844: * stored in the specified data buffer. 845: * 846: * @param x the x-coordinate. 847: * @param y the y-coordinate. 848: * @param iArray the pixel sample values (<code>null</code> not permitted). 849: * @param data the data buffer (<code>null</code> not permitted). 850: * 851: * @see #getPixel(int, int, int[], DataBuffer) 852: */ 853: public void setPixel(int x, int y, int[] iArray, DataBuffer data) 854: { 855: int offset = pixelStride * x + scanlineStride * y; 856: for (int b = 0; b < numBands; b++) 857: data.setElem(bankIndices[b], offset + bandOffsets[b], iArray[b]); 858: } 859: 860: /** 861: * Sets the sample value for band <code>b</code> of the pixel at location 862: * <code>(x, y)</code> in the specified data buffer. 863: * 864: * @param x the x-coordinate. 865: * @param y the y-coordinate. 866: * @param b the band index. 867: * @param s the sample value. 868: * @param data the data buffer (<code>null</code> not permitted). 869: * 870: * @see #getSample(int, int, int, DataBuffer) 871: */ 872: public void setSample(int x, int y, int b, int s, DataBuffer data) 873: { 874: data.setElem(bankIndices[b], getOffset(x, y, b), s); 875: } 876: 877: /** 878: * Tests this sample model for equality with an arbitrary object. Returns 879: * <code>true</code> if and only if: 880: * <ul> 881: * <li><code>obj</code> is not <code>null</code>;</li> 882: * <li><code>obj</code> is an instance of <code>ComponentSampleModel</code>; 883: * </li> 884: * <li>both models have the same values for the <code>dataType</code>, 885: * <code>width</code>, <code>height</code>, <code>pixelStride</code>, 886: * <code>scanlineStride</code>, <code>bandOffsets</code> and 887: * <code>bankIndices</code> fields.</li> 888: * </ul> 889: * 890: * @param obj the object to test (<code>null</code> permitted). 891: * 892: * @return <code>true</code> if this sample model is equal to 893: * <code>obj</code>, and <code>false</code> otherwise. 894: */ 895: public boolean equals(Object obj) 896: { 897: if (obj == null) 898: return false; 899: if (! (obj instanceof ComponentSampleModel)) 900: return false; 901: ComponentSampleModel that = (ComponentSampleModel) obj; 902: if (this.dataType != that.dataType) 903: return false; 904: if (this.width != that.width) 905: return false; 906: if (this.height != that.height) 907: return false; 908: if (this.pixelStride != that.pixelStride) 909: return false; 910: if (this.scanlineStride != that.scanlineStride) 911: return false; 912: if (! Arrays.equals(this.bandOffsets, that.bandOffsets)) 913: return false; 914: if (! Arrays.equals(this.bankIndices, that.bankIndices)) 915: return false; 916: // couldn't find any difference, so... 917: return true; 918: } 919: 920: /** 921: * Returns a hash code for this sample model. 922: * 923: * @return The hash code. 924: */ 925: public int hashCode() 926: { 927: // this computation is based on the method described in Chapter 3 928: // of Joshua Bloch's Effective Java... 929: int result = 17; 930: result = 37 * result + dataType; 931: result = 37 * result + width; 932: result = 37 * result + height; 933: result = 37 * result + pixelStride; 934: result = 37 * result + scanlineStride; 935: for (int i = 0; i < bandOffsets.length; i++) 936: result = 37 * result + bandOffsets[i]; 937: for (int i = 0; i < bankIndices.length; i++) 938: result = 37 * result + bankIndices[i]; 939: return result; 940: } 941: }