1 /* 2 * Copyright (c) 1997, 2018, 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 /** 39 * The {@code MultiPixelPackedSampleModel} class represents 40 * one-banded images and can pack multiple one-sample 41 * pixels into one data element. Pixels are not allowed to span data elements. 42 * The data type can be DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT, 43 * or DataBuffer.TYPE_INT. Each pixel must be a power of 2 number of bits 44 * and a power of 2 number of pixels must fit exactly in one data element. 45 * Pixel bit stride is equal to the number of bits per pixel. Scanline 46 * stride is in data elements and the last several data elements might be 47 * padded with unused pixels. Data bit offset is the offset in bits from 48 * the beginning of the {@link DataBuffer} to the first pixel and must be 49 * a multiple of pixel bit stride. 50 * <p> 51 * The following code illustrates extracting the bits for pixel 52 * <code>x, y</code> from {@code DataBuffer data} 53 * and storing the pixel data in data elements of type 54 * {@code dataType}: 55 * <pre>{@code 56 * int dataElementSize = DataBuffer.getDataTypeSize(dataType); 57 * int bitnum = dataBitOffset + x*pixelBitStride; 58 * int element = data.getElem(y*scanlineStride + bitnum/dataElementSize); 59 * int shift = dataElementSize - (bitnum & (dataElementSize-1)) 60 * - pixelBitStride; 61 * int pixel = (element >> shift) & ((1 << pixelBitStride) - 1); 62 * }</pre> 63 */ 64 65 public class MultiPixelPackedSampleModel extends SampleModel 66 { 67 /** The number of bits from one pixel to the next. */ 68 int pixelBitStride; 69 70 /** Bitmask that extracts the rightmost pixel of a data element. */ 71 int bitMask; 72 73 /** 74 * The number of pixels that fit in a data element. Also used 75 * as the number of bits per pixel. 76 */ 77 int pixelsPerDataElement; 78 79 /** The size of a data element in bits. */ 80 int dataElementSize; 81 82 /** The bit offset into the data array where the first pixel begins. 83 */ 84 int dataBitOffset; 85 86 /** ScanlineStride of the data buffer described in data array elements. */ 87 int scanlineStride; 88 89 /** 90 * Constructs a {@code MultiPixelPackedSampleModel} with the 91 * specified data type, width, height and number of bits per pixel. 92 * @param dataType the data type for storing samples 93 * @param w the width, in pixels, of the region of 94 * image data described 95 * @param h the height, in pixels, of the region of 96 * image data described 97 * @param numberOfBits the number of bits per pixel 98 * @throws IllegalArgumentException if {@code dataType} is not 99 * either {@code DataBuffer.TYPE_BYTE}, 100 * {@code DataBuffer.TYPE_USHORT}, or 101 * {@code DataBuffer.TYPE_INT} 102 */ MultiPixelPackedSampleModel(int dataType, int w, int h, int numberOfBits)103 public MultiPixelPackedSampleModel(int dataType, 104 int w, 105 int h, 106 int numberOfBits) { 107 this(dataType,w,h, 108 numberOfBits, 109 (w*numberOfBits+DataBuffer.getDataTypeSize(dataType)-1)/ 110 DataBuffer.getDataTypeSize(dataType), 111 0); 112 if (dataType != DataBuffer.TYPE_BYTE && 113 dataType != DataBuffer.TYPE_USHORT && 114 dataType != DataBuffer.TYPE_INT) { 115 throw new IllegalArgumentException("Unsupported data type "+ 116 dataType); 117 } 118 } 119 120 /** 121 * Constructs a {@code MultiPixelPackedSampleModel} with 122 * specified data type, width, height, number of bits per pixel, 123 * scanline stride and data bit offset. 124 * @param dataType the data type for storing samples 125 * @param w the width, in pixels, of the region of 126 * image data described 127 * @param h the height, in pixels, of the region of 128 * image data described 129 * @param numberOfBits the number of bits per pixel 130 * @param scanlineStride the line stride of the image data 131 * @param dataBitOffset the data bit offset for the region of image 132 * data described 133 * @exception RasterFormatException if the number of bits per pixel 134 * is not a power of 2 or if a power of 2 number of 135 * pixels do not fit in one data element. 136 * @throws IllegalArgumentException if {@code w} or 137 * {@code h} is not greater than 0 138 * @throws IllegalArgumentException if {@code dataType} is not 139 * either {@code DataBuffer.TYPE_BYTE}, 140 * {@code DataBuffer.TYPE_USHORT}, or 141 * {@code DataBuffer.TYPE_INT} 142 */ MultiPixelPackedSampleModel(int dataType, int w, int h, int numberOfBits, int scanlineStride, int dataBitOffset)143 public MultiPixelPackedSampleModel(int dataType, int w, int h, 144 int numberOfBits, 145 int scanlineStride, 146 int dataBitOffset) { 147 super(dataType, w, h, 1); 148 if (dataType != DataBuffer.TYPE_BYTE && 149 dataType != DataBuffer.TYPE_USHORT && 150 dataType != DataBuffer.TYPE_INT) { 151 throw new IllegalArgumentException("Unsupported data type "+ 152 dataType); 153 } 154 this.dataType = dataType; 155 this.pixelBitStride = numberOfBits; 156 this.scanlineStride = scanlineStride; 157 this.dataBitOffset = dataBitOffset; 158 this.dataElementSize = DataBuffer.getDataTypeSize(dataType); 159 this.pixelsPerDataElement = dataElementSize/numberOfBits; 160 if (pixelsPerDataElement*numberOfBits != dataElementSize) { 161 throw new RasterFormatException("MultiPixelPackedSampleModel " + 162 "does not allow pixels to " + 163 "span data element boundaries"); 164 } 165 this.bitMask = (1 << numberOfBits) - 1; 166 } 167 168 169 /** 170 * Creates a new {@code MultiPixelPackedSampleModel} with the 171 * specified width and height. The new 172 * {@code MultiPixelPackedSampleModel} has the 173 * same storage data type and number of bits per pixel as this 174 * {@code MultiPixelPackedSampleModel}. 175 * @param w the specified width 176 * @param h the specified height 177 * @return a {@link SampleModel} with the specified width and height 178 * and with the same storage data type and number of bits per pixel 179 * as this {@code MultiPixelPackedSampleModel}. 180 * @throws IllegalArgumentException if {@code w} or 181 * {@code h} is not greater than 0 182 */ createCompatibleSampleModel(int w, int h)183 public SampleModel createCompatibleSampleModel(int w, int h) { 184 SampleModel sampleModel = 185 new MultiPixelPackedSampleModel(dataType, w, h, pixelBitStride); 186 return sampleModel; 187 } 188 189 /** 190 * Creates a {@code DataBuffer} that corresponds to this 191 * {@code MultiPixelPackedSampleModel}. The 192 * {@code DataBuffer} object's data type and size 193 * is consistent with this {@code MultiPixelPackedSampleModel}. 194 * The {@code DataBuffer} has a single bank. 195 * @return a {@code DataBuffer} with the same data type and 196 * size as this {@code MultiPixelPackedSampleModel}. 197 */ createDataBuffer()198 public DataBuffer createDataBuffer() { 199 DataBuffer dataBuffer = null; 200 201 int size = scanlineStride*height; 202 switch (dataType) { 203 case DataBuffer.TYPE_BYTE: 204 dataBuffer = new DataBufferByte(size+(dataBitOffset+7)/8); 205 break; 206 case DataBuffer.TYPE_USHORT: 207 dataBuffer = new DataBufferUShort(size+(dataBitOffset+15)/16); 208 break; 209 case DataBuffer.TYPE_INT: 210 dataBuffer = new DataBufferInt(size+(dataBitOffset+31)/32); 211 break; 212 } 213 return dataBuffer; 214 } 215 216 /** 217 * Returns the number of data elements needed to transfer one pixel 218 * via the {@link #getDataElements} and {@link #setDataElements} 219 * methods. For a {@code MultiPixelPackedSampleModel}, this is 220 * one. 221 * @return the number of data elements. 222 */ getNumDataElements()223 public int getNumDataElements() { 224 return 1; 225 } 226 227 /** 228 * Returns the number of bits per sample for all bands. 229 * @return the number of bits per sample. 230 */ getSampleSize()231 public int[] getSampleSize() { 232 int[] sampleSize = {pixelBitStride}; 233 return sampleSize; 234 } 235 236 /** 237 * Returns the number of bits per sample for the specified band. 238 * @param band the specified band 239 * @return the number of bits per sample for the specified band. 240 */ getSampleSize(int band)241 public int getSampleSize(int band) { 242 return pixelBitStride; 243 } 244 245 /** 246 * Returns the offset of pixel (x, y) in data array elements. 247 * @param x the X coordinate of the specified pixel 248 * @param y the Y coordinate of the specified pixel 249 * @return the offset of the specified pixel. 250 */ getOffset(int x, int y)251 public int getOffset(int x, int y) { 252 int offset = y * scanlineStride; 253 offset += (x*pixelBitStride+dataBitOffset)/dataElementSize; 254 return offset; 255 } 256 257 /** 258 * Returns the offset, in bits, into the data element in which it is 259 * stored for the {@code x}th pixel of a scanline. 260 * This offset is the same for all scanlines. 261 * @param x the specified pixel 262 * @return the bit offset of the specified pixel. 263 */ getBitOffset(int x)264 public int getBitOffset(int x){ 265 return (x*pixelBitStride+dataBitOffset)%dataElementSize; 266 } 267 268 /** 269 * Returns the scanline stride. 270 * @return the scanline stride of this 271 * {@code MultiPixelPackedSampleModel}. 272 */ getScanlineStride()273 public int getScanlineStride() { 274 return scanlineStride; 275 } 276 277 /** 278 * Returns the pixel bit stride in bits. This value is the same as 279 * the number of bits per pixel. 280 * @return the {@code pixelBitStride} of this 281 * {@code MultiPixelPackedSampleModel}. 282 */ getPixelBitStride()283 public int getPixelBitStride() { 284 return pixelBitStride; 285 } 286 287 /** 288 * Returns the data bit offset in bits. 289 * @return the {@code dataBitOffset} of this 290 * {@code MultiPixelPackedSampleModel}. 291 */ getDataBitOffset()292 public int getDataBitOffset() { 293 return dataBitOffset; 294 } 295 296 /** 297 * Returns the TransferType used to transfer pixels by way of the 298 * {@code getDataElements} and {@code setDataElements} 299 * methods. The TransferType might or might not be the same as the 300 * storage DataType. The TransferType is one of 301 * DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT, 302 * or DataBuffer.TYPE_INT. 303 * @return the transfertype. 304 */ getTransferType()305 public int getTransferType() { 306 if (pixelBitStride > 16) 307 return DataBuffer.TYPE_INT; 308 else if (pixelBitStride > 8) 309 return DataBuffer.TYPE_USHORT; 310 else 311 return DataBuffer.TYPE_BYTE; 312 } 313 314 /** 315 * Creates a new {@code MultiPixelPackedSampleModel} with a 316 * subset of the bands of this 317 * {@code MultiPixelPackedSampleModel}. Since a 318 * {@code MultiPixelPackedSampleModel} only has one band, the 319 * bands argument must have a length of one and indicate the zeroth 320 * band. 321 * @param bands the specified bands 322 * @return a new {@code SampleModel} with a subset of bands of 323 * this {@code MultiPixelPackedSampleModel}. 324 * @exception RasterFormatException if the number of bands requested 325 * is not one. 326 * @throws IllegalArgumentException if {@code w} or 327 * {@code h} is not greater than 0 328 */ createSubsetSampleModel(int[] bands)329 public SampleModel createSubsetSampleModel(int[] bands) { 330 if (bands != null) { 331 if (bands.length != 1) 332 throw new RasterFormatException("MultiPixelPackedSampleModel has " 333 + "only one band."); 334 } 335 SampleModel sm = createCompatibleSampleModel(width, height); 336 return sm; 337 } 338 339 /** 340 * Returns as {@code int} the sample in a specified band for the 341 * pixel located at (x, y). An 342 * {@code ArrayIndexOutOfBoundsException} is thrown if the 343 * coordinates are not in bounds. 344 * @param x the X coordinate of the specified pixel 345 * @param y the Y coordinate of the specified pixel 346 * @param b the band to return, which is assumed to be 0 347 * @param data the {@code DataBuffer} containing the image 348 * data 349 * @return the specified band containing the sample of the specified 350 * pixel. 351 * @exception ArrayIndexOutOfBoundsException if the specified 352 * coordinates are not in bounds. 353 * @see #setSample(int, int, int, int, DataBuffer) 354 */ getSample(int x, int y, int b, DataBuffer data)355 public int getSample(int x, int y, int b, DataBuffer data) { 356 // 'b' must be 0 357 if ((x < 0) || (y < 0) || (x >= width) || (y >= height) || 358 (b != 0)) { 359 throw new ArrayIndexOutOfBoundsException 360 ("Coordinate out of bounds!"); 361 } 362 int bitnum = dataBitOffset + x*pixelBitStride; 363 int element = data.getElem(y*scanlineStride + bitnum/dataElementSize); 364 int shift = dataElementSize - (bitnum & (dataElementSize-1)) 365 - pixelBitStride; 366 return (element >> shift) & bitMask; 367 } 368 369 /** 370 * Sets a sample in the specified band for the pixel located at 371 * (x, y) in the {@code DataBuffer} using an 372 * {@code int} for input. 373 * An {@code ArrayIndexOutOfBoundsException} is thrown if the 374 * coordinates are not in bounds. 375 * @param x the X coordinate of the specified pixel 376 * @param y the Y coordinate of the specified pixel 377 * @param b the band to return, which is assumed to be 0 378 * @param s the input sample as an {@code int} 379 * @param data the {@code DataBuffer} where image data is stored 380 * @exception ArrayIndexOutOfBoundsException if the coordinates are 381 * not in bounds. 382 * @see #getSample(int, int, int, DataBuffer) 383 */ setSample(int x, int y, int b, int s, DataBuffer data)384 public void setSample(int x, int y, int b, int s, 385 DataBuffer data) { 386 // 'b' must be 0 387 if ((x < 0) || (y < 0) || (x >= width) || (y >= height) || 388 (b != 0)) { 389 throw new ArrayIndexOutOfBoundsException 390 ("Coordinate out of bounds!"); 391 } 392 int bitnum = dataBitOffset + x * pixelBitStride; 393 int index = y * scanlineStride + (bitnum / dataElementSize); 394 int shift = dataElementSize - (bitnum & (dataElementSize-1)) 395 - pixelBitStride; 396 int element = data.getElem(index); 397 element &= ~(bitMask << shift); 398 element |= (s & bitMask) << shift; 399 data.setElem(index,element); 400 } 401 402 /** 403 * Returns data for a single pixel in a primitive array of type 404 * TransferType. For a {@code MultiPixelPackedSampleModel}, 405 * the array has one element, and the type is the smallest of 406 * DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT, or DataBuffer.TYPE_INT 407 * that can hold a single pixel. Generally, {@code obj} 408 * should be passed in as {@code null}, so that the 409 * {@code Object} is created automatically and is the 410 * correct primitive data type. 411 * <p> 412 * The following code illustrates transferring data for one pixel from 413 * {@code DataBuffer db1}, whose storage layout is 414 * described by {@code MultiPixelPackedSampleModel} 415 * {@code mppsm1}, to {@code DataBuffer db2}, 416 * whose storage layout is described by 417 * {@code MultiPixelPackedSampleModel mppsm2}. 418 * The transfer is generally more efficient than using 419 * {@code getPixel} or {@code setPixel}. 420 * <pre> 421 * MultiPixelPackedSampleModel mppsm1, mppsm2; 422 * DataBufferInt db1, db2; 423 * mppsm2.setDataElements(x, y, mppsm1.getDataElements(x, y, null, 424 * db1), db2); 425 * </pre> 426 * Using {@code getDataElements} or {@code setDataElements} 427 * to transfer between two {@code DataBuffer/SampleModel} pairs 428 * is legitimate if the {@code SampleModels} have the same number 429 * of bands, corresponding bands have the same number of 430 * bits per sample, and the TransferTypes are the same. 431 * <p> 432 * If {@code obj} is not {@code null}, it should be a 433 * primitive array of type TransferType. Otherwise, a 434 * {@code ClassCastException} is thrown. An 435 * {@code ArrayIndexOutOfBoundsException} is thrown if the 436 * coordinates are not in bounds, or if {@code obj} is not 437 * {@code null} and is not large enough to hold the pixel data. 438 * @param x the X coordinate of the specified pixel 439 * @param y the Y coordinate of the specified pixel 440 * @param obj a primitive array in which to return the pixel data or 441 * {@code null}. 442 * @param data the {@code DataBuffer} containing the image data. 443 * @return an {@code Object} containing data for the specified 444 * pixel. 445 * @exception ClassCastException if {@code obj} is not a 446 * primitive array of type TransferType or is not {@code null} 447 * @exception ArrayIndexOutOfBoundsException if the coordinates are 448 * not in bounds, or if {@code obj} is not {@code null} or 449 * not large enough to hold the pixel data 450 * @see #setDataElements(int, int, Object, DataBuffer) 451 */ getDataElements(int x, int y, Object obj, DataBuffer data)452 public Object getDataElements(int x, int y, Object obj, DataBuffer data) { 453 if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) { 454 throw new ArrayIndexOutOfBoundsException 455 ("Coordinate out of bounds!"); 456 } 457 458 int type = getTransferType(); 459 int bitnum = dataBitOffset + x*pixelBitStride; 460 int shift = dataElementSize - (bitnum & (dataElementSize-1)) 461 - pixelBitStride; 462 int element = 0; 463 464 switch(type) { 465 466 case DataBuffer.TYPE_BYTE: 467 468 byte[] bdata; 469 470 if (obj == null) 471 bdata = new byte[1]; 472 else 473 bdata = (byte[])obj; 474 475 element = data.getElem(y*scanlineStride + 476 bitnum/dataElementSize); 477 bdata[0] = (byte)((element >> shift) & bitMask); 478 479 obj = (Object)bdata; 480 break; 481 482 case DataBuffer.TYPE_USHORT: 483 484 short[] sdata; 485 486 if (obj == null) 487 sdata = new short[1]; 488 else 489 sdata = (short[])obj; 490 491 element = data.getElem(y*scanlineStride + 492 bitnum/dataElementSize); 493 sdata[0] = (short)((element >> shift) & bitMask); 494 495 obj = (Object)sdata; 496 break; 497 498 case DataBuffer.TYPE_INT: 499 500 int[] idata; 501 502 if (obj == null) 503 idata = new int[1]; 504 else 505 idata = (int[])obj; 506 507 element = data.getElem(y*scanlineStride + 508 bitnum/dataElementSize); 509 idata[0] = (element >> shift) & bitMask; 510 511 obj = (Object)idata; 512 break; 513 } 514 515 return obj; 516 } 517 518 /** 519 * Returns the specified single band pixel in the first element 520 * of an {@code int} array. 521 * {@code ArrayIndexOutOfBoundsException} is thrown if the 522 * coordinates are not in bounds. 523 * @param x the X coordinate of the specified pixel 524 * @param y the Y coordinate of the specified pixel 525 * @param iArray the array containing the pixel to be returned or 526 * {@code null} 527 * @param data the {@code DataBuffer} where image data is stored 528 * @return an array containing the specified pixel. 529 * @exception ArrayIndexOutOfBoundsException if the coordinates 530 * are not in bounds 531 * @see #setPixel(int, int, int[], DataBuffer) 532 */ getPixel(int x, int y, int[] iArray, DataBuffer data)533 public int[] getPixel(int x, int y, int[] iArray, DataBuffer data) { 534 if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) { 535 throw new ArrayIndexOutOfBoundsException 536 ("Coordinate out of bounds!"); 537 } 538 int[] pixels; 539 if (iArray != null) { 540 pixels = iArray; 541 } else { 542 pixels = new int [numBands]; 543 } 544 int bitnum = dataBitOffset + x*pixelBitStride; 545 int element = data.getElem(y*scanlineStride + bitnum/dataElementSize); 546 int shift = dataElementSize - (bitnum & (dataElementSize-1)) 547 - pixelBitStride; 548 pixels[0] = (element >> shift) & bitMask; 549 return pixels; 550 } 551 552 /** 553 * Sets the data for a single pixel in the specified 554 * {@code DataBuffer} from a primitive array of type 555 * TransferType. For a {@code MultiPixelPackedSampleModel}, 556 * only the first element of the array holds valid data, 557 * and the type must be the smallest of 558 * DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT, or DataBuffer.TYPE_INT 559 * that can hold a single pixel. 560 * <p> 561 * The following code illustrates transferring data for one pixel from 562 * {@code DataBuffer db1}, whose storage layout is 563 * described by {@code MultiPixelPackedSampleModel} 564 * {@code mppsm1}, to {@code DataBuffer db2}, 565 * whose storage layout is described by 566 * {@code MultiPixelPackedSampleModel mppsm2}. 567 * The transfer is generally more efficient than using 568 * {@code getPixel} or {@code setPixel}. 569 * <pre> 570 * MultiPixelPackedSampleModel mppsm1, mppsm2; 571 * DataBufferInt db1, db2; 572 * mppsm2.setDataElements(x, y, mppsm1.getDataElements(x, y, null, 573 * db1), db2); 574 * </pre> 575 * Using {@code getDataElements} or {@code setDataElements} to 576 * transfer between two {@code DataBuffer/SampleModel} pairs is 577 * legitimate if the {@code SampleModel} objects have 578 * the same number of bands, corresponding bands have the same number of 579 * bits per sample, and the TransferTypes are the same. 580 * <p> 581 * {@code obj} must be a primitive array of type TransferType. 582 * Otherwise, a {@code ClassCastException} is thrown. An 583 * {@code ArrayIndexOutOfBoundsException} is thrown if the 584 * coordinates are not in bounds, or if {@code obj} is not large 585 * enough to hold the pixel data. 586 * @param x the X coordinate of the pixel location 587 * @param y the Y coordinate of the pixel location 588 * @param obj a primitive array containing pixel data 589 * @param data the {@code DataBuffer} containing the image data 590 * @see #getDataElements(int, int, Object, DataBuffer) 591 */ setDataElements(int x, int y, Object obj, DataBuffer data)592 public void setDataElements(int x, int y, Object obj, DataBuffer data) { 593 if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) { 594 throw new ArrayIndexOutOfBoundsException 595 ("Coordinate out of bounds!"); 596 } 597 598 int type = getTransferType(); 599 int bitnum = dataBitOffset + x * pixelBitStride; 600 int index = y * scanlineStride + (bitnum / dataElementSize); 601 int shift = dataElementSize - (bitnum & (dataElementSize-1)) 602 - pixelBitStride; 603 int element = data.getElem(index); 604 element &= ~(bitMask << shift); 605 606 switch(type) { 607 608 case DataBuffer.TYPE_BYTE: 609 610 byte[] barray = (byte[])obj; 611 element |= ( ((int)(barray[0])&0xff) & bitMask) << shift; 612 data.setElem(index, element); 613 break; 614 615 case DataBuffer.TYPE_USHORT: 616 617 short[] sarray = (short[])obj; 618 element |= ( ((int)(sarray[0])&0xffff) & bitMask) << shift; 619 data.setElem(index, element); 620 break; 621 622 case DataBuffer.TYPE_INT: 623 624 int[] iarray = (int[])obj; 625 element |= (iarray[0] & bitMask) << shift; 626 data.setElem(index, element); 627 break; 628 } 629 } 630 631 /** 632 * Sets a pixel in the {@code DataBuffer} using an 633 * {@code int} array for input. 634 * {@code ArrayIndexOutOfBoundsException} is thrown if 635 * the coordinates are not in bounds. 636 * @param x the X coordinate of the pixel location 637 * @param y the Y coordinate of the pixel location 638 * @param iArray the input pixel in an {@code int} array 639 * @param data the {@code DataBuffer} containing the image data 640 * @see #getPixel(int, int, int[], DataBuffer) 641 */ setPixel(int x, int y, int[] iArray, DataBuffer data)642 public void setPixel(int x, int y, int[] iArray, DataBuffer data) { 643 if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) { 644 throw new ArrayIndexOutOfBoundsException 645 ("Coordinate out of bounds!"); 646 } 647 int bitnum = dataBitOffset + x * pixelBitStride; 648 int index = y * scanlineStride + (bitnum / dataElementSize); 649 int shift = dataElementSize - (bitnum & (dataElementSize-1)) 650 - pixelBitStride; 651 int element = data.getElem(index); 652 element &= ~(bitMask << shift); 653 element |= (iArray[0] & bitMask) << shift; 654 data.setElem(index,element); 655 } 656 equals(Object o)657 public boolean equals(Object o) { 658 if ((o == null) || !(o instanceof MultiPixelPackedSampleModel)) { 659 return false; 660 } 661 662 MultiPixelPackedSampleModel that = (MultiPixelPackedSampleModel)o; 663 return this.width == that.width && 664 this.height == that.height && 665 this.numBands == that.numBands && 666 this.dataType == that.dataType && 667 this.pixelBitStride == that.pixelBitStride && 668 this.bitMask == that.bitMask && 669 this.pixelsPerDataElement == that.pixelsPerDataElement && 670 this.dataElementSize == that.dataElementSize && 671 this.dataBitOffset == that.dataBitOffset && 672 this.scanlineStride == that.scanlineStride; 673 } 674 675 // If we implement equals() we must also implement hashCode hashCode()676 public int hashCode() { 677 int hash = 0; 678 hash = width; 679 hash <<= 8; 680 hash ^= height; 681 hash <<= 8; 682 hash ^= numBands; 683 hash <<= 8; 684 hash ^= dataType; 685 hash <<= 8; 686 hash ^= pixelBitStride; 687 hash <<= 8; 688 hash ^= bitMask; 689 hash <<= 8; 690 hash ^= pixelsPerDataElement; 691 hash <<= 8; 692 hash ^= dataElementSize; 693 hash <<= 8; 694 hash ^= dataBitOffset; 695 hash <<= 8; 696 hash ^= scanlineStride; 697 return hash; 698 } 699 } 700