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 package sun.awt.image; 27 import java.awt.image.Raster; 28 import java.awt.image.WritableRaster; 29 import java.awt.image.RasterFormatException; 30 import java.awt.image.SampleModel; 31 import java.awt.image.BandedSampleModel; 32 import java.awt.image.DataBufferUShort; 33 import java.awt.Rectangle; 34 import java.awt.Point; 35 36 /** 37 * This class defines a Raster with pixels consisting of multiple 16-bit 38 * samples stored in separate arrays for each band. Operations on 39 * sets of pixels are performed on a given band of each pixel 40 * in the set before moving on to the next band. The arrays used 41 * for storage may be distinct or shared between some or all of 42 * the bands. 43 * There is only one pixel stride and one scanline stride for all 44 * bands. This type of Raster can be used with a 45 * ComponentColorModel. This class requires a BandedSampleModel. 46 * 47 */ 48 public class ShortBandedRaster extends SunWritableRaster { 49 50 /** Data offsets for each band of image data. */ 51 int[] dataOffsets; 52 53 /** Scanline stride of the image data contained in this Raster. */ 54 int scanlineStride; 55 56 /** The image data array. */ 57 short[][] data; 58 59 /** A cached copy of minX + width for use in bounds checks. */ 60 private int maxX; 61 62 /** A cached copy of minY + height for use in bounds checks. */ 63 private int maxY; 64 65 /** 66 * Constructs a ShortBandedRaster with the given SampleModel. 67 * The Raster's upper left corner is origin and it is the same 68 * size as the SampleModel. A DataBuffer large enough to describe the 69 * Raster is automatically created. SampleModel must be of type 70 * BandedSampleModel. 71 * @param sampleModel The SampleModel that specifies the layout. 72 * @param origin The Point that specified the origin. 73 */ ShortBandedRaster(SampleModel sampleModel, Point origin)74 public ShortBandedRaster(SampleModel sampleModel, Point origin) { 75 this(sampleModel, 76 (DataBufferUShort) sampleModel.createDataBuffer(), 77 new Rectangle(origin.x, 78 origin.y, 79 sampleModel.getWidth(), 80 sampleModel.getHeight()), 81 origin, 82 null); 83 } 84 85 /** 86 * Constructs a ShortBandedRaster with the given SampleModel 87 * and DataBuffer. The Raster's upper left corner is origin and 88 * it is the same size as the SampleModel. The DataBuffer is not 89 * initialized and must be a DataBufferUShort compatible with SampleModel. 90 * SampleModel must be of type BandedSampleModel. 91 * @param sampleModel The SampleModel that specifies the layout. 92 * @param dataBuffer The DataBufferUShort that contains the image data. 93 * @param origin The Point that specifies the origin. 94 */ ShortBandedRaster(SampleModel sampleModel, DataBufferUShort dataBuffer, Point origin)95 public ShortBandedRaster(SampleModel sampleModel, 96 DataBufferUShort dataBuffer, 97 Point origin) 98 { 99 this(sampleModel, dataBuffer, 100 new Rectangle(origin.x, origin.y, 101 sampleModel.getWidth(), 102 sampleModel.getHeight()), 103 origin, null); 104 } 105 106 /** 107 * Constructs a ShortBandedRaster with the given SampleModel, 108 * DataBuffer, and parent. DataBuffer must be a DataBufferUShort and 109 * SampleModel must be of type BandedSampleModel. 110 * When translated into the base Raster's 111 * coordinate system, aRegion must be contained by the base Raster. 112 * Origin is the coordinate in the new Raster's coordinate system of 113 * the origin of the base Raster. (The base Raster is the Raster's 114 * ancestor which has no parent.) 115 * 116 * Note that this constructor should generally be called by other 117 * constructors or create methods, it should not be used directly. 118 * @param sampleModel The SampleModel that specifies the layout. 119 * @param dataBuffer The DataBufferUShort that contains the image data. 120 * @param aRegion The Rectangle that specifies the image area. 121 * @param origin The Point that specifies the origin. 122 * @param parent The parent (if any) of this raster. 123 */ ShortBandedRaster(SampleModel sampleModel, DataBufferUShort dataBuffer, Rectangle aRegion, Point origin, ShortBandedRaster parent)124 public ShortBandedRaster(SampleModel sampleModel, 125 DataBufferUShort dataBuffer, 126 Rectangle aRegion, 127 Point origin, 128 ShortBandedRaster parent) 129 { 130 super(sampleModel, dataBuffer, aRegion, origin, parent); 131 this.maxX = minX + width; 132 this.maxY = minY + height; 133 134 if (sampleModel instanceof BandedSampleModel) { 135 BandedSampleModel bsm = (BandedSampleModel)sampleModel; 136 this.scanlineStride = bsm.getScanlineStride(); 137 int[] bankIndices = bsm.getBankIndices(); 138 int[] bandOffsets = bsm.getBandOffsets(); 139 int[] dOffsets = dataBuffer.getOffsets(); 140 dataOffsets = new int[bankIndices.length]; 141 data = new short[bankIndices.length][]; 142 int xOffset = aRegion.x - origin.x; 143 int yOffset = aRegion.y - origin.y; 144 for (int i = 0; i < bankIndices.length; i++) { 145 data[i] = stealData(dataBuffer, bankIndices[i]); 146 dataOffsets[i] = dOffsets[bankIndices[i]] + 147 xOffset + yOffset*scanlineStride + bandOffsets[i]; 148 } 149 } else { 150 throw new RasterFormatException("ShortBandedRasters must have "+ 151 "BandedSampleModels"); 152 } 153 verify(); 154 } 155 156 /** 157 * Returns a copy of the data offsets array. For each band the data offset 158 * is the index into the band's data array, of the first sample of the 159 * band. 160 */ getDataOffsets()161 public int[] getDataOffsets() { 162 return dataOffsets.clone(); 163 } 164 165 /** 166 * Returns the data offset for the specified band. The data offset 167 * is the index into the band's data array 168 * in which the first sample of the first scanline is stored. 169 * @param band The band whose offset is returned. 170 */ getDataOffset(int band)171 public int getDataOffset(int band) { 172 return dataOffsets[band]; 173 } 174 175 /** 176 * Returns the scanline stride -- the number of data array elements between 177 * a given sample and the sample in the same column 178 * of the next row in the same band. 179 */ getScanlineStride()180 public int getScanlineStride() { 181 return scanlineStride; 182 } 183 184 /** 185 * Returns the pixel stride, which is always equal to one for 186 * a Raster with a BandedSampleModel. 187 */ getPixelStride()188 public int getPixelStride() { 189 return 1; 190 } 191 192 /** 193 * Returns a reference to the entire data array. 194 */ getDataStorage()195 public short[][] getDataStorage() { 196 return data; 197 } 198 199 /** 200 * Returns a reference to the specific band data array. 201 */ getDataStorage(int band)202 public short[] getDataStorage(int band) { 203 return data[band]; 204 } 205 206 /** 207 * Returns the data elements for all bands at the specified 208 * location. 209 * An ArrayIndexOutOfBounds exception will be thrown at runtime 210 * if the pixel coordinate is out of bounds. 211 * A ClassCastException will be thrown if the input object is non null 212 * and references anything other than an array of transferType. 213 * @param x The X coordinate of the pixel location. 214 * @param y The Y coordinate of the pixel location. 215 * @param obj An object reference to an array of type defined by 216 * getTransferType() and length getNumDataElements(). 217 * If null an array of appropriate type and size will be 218 * allocated. 219 * @return An object reference to an array of type defined by 220 * getTransferType() with the request pixel data. 221 */ getDataElements(int x, int y, Object obj)222 public Object getDataElements(int x, int y, Object obj) { 223 if ((x < this.minX) || (y < this.minY) || 224 (x >= this.maxX) || (y >= this.maxY)) { 225 throw new ArrayIndexOutOfBoundsException 226 ("Coordinate out of bounds!"); 227 } 228 short[] outData; 229 if (obj == null) { 230 outData = new short[numDataElements]; 231 } else { 232 outData = (short[])obj; 233 } 234 235 int off = (y-minY)*scanlineStride + (x-minX); 236 237 for (int band = 0; band < numDataElements; band++) { 238 outData[band] = data[band][dataOffsets[band] + off]; 239 } 240 241 return outData; 242 } 243 244 /** 245 * Returns an array of data elements from the specified rectangular 246 * region. 247 * An ArrayIndexOutOfBounds exception will be thrown at runtime 248 * if the pixel coordinates are out of bounds. 249 * <pre> 250 * short[] bandData = (short[])Raster.getDataElements(x, y, w, h, null); 251 * int numDataElements = Raster.getnumDataElements(); 252 * short[] pixel = new short[numDataElements]; 253 * // To find a data element at location (x2, y2) 254 * System.arraycopy(bandData, ((y2-y)*w + (x2-x))*numDataElements, 255 * pixel, 0, numDataElements); 256 * </pre> 257 * @param x The X coordinate of the upper left pixel location. 258 * @param y The Y coordinate of the upper left pixel location. 259 * @param w Width of the pixel rectangle. 260 * @param h Height of the pixel rectangle. 261 * @param obj An object reference to an array of type defined by 262 * getTransferType() and length w*h*getNumDataElements(). 263 * If null an array of appropriate type and size will be 264 * allocated. 265 * @return An object reference to an array of type defined by 266 * getTransferType() with the request pixel data. 267 */ getDataElements(int x, int y, int w, int h, Object obj)268 public Object getDataElements(int x, int y, int w, int h, Object obj) { 269 if ((x < this.minX) || (y < this.minY) || 270 (x + w > this.maxX) || (y + h > this.maxY)) { 271 throw new ArrayIndexOutOfBoundsException 272 ("Coordinate out of bounds!"); 273 } 274 short[] outData; 275 if (obj == null) { 276 outData = new short[numDataElements*w*h]; 277 } else { 278 outData = (short[])obj; 279 } 280 int yoff = (y-minY)*scanlineStride + (x-minX); 281 282 for (int c = 0; c < numDataElements; c++) { 283 int off = c; 284 short[] bank = data[c]; 285 int dataOffset = dataOffsets[c]; 286 287 int yoff2 = yoff; 288 for (int ystart=0; ystart < h; ystart++, yoff2 += scanlineStride) { 289 int xoff = dataOffset + yoff2; 290 for (int xstart=0; xstart < w; xstart++) { 291 outData[off] = bank[xoff++]; 292 off += numDataElements; 293 } 294 } 295 } 296 297 return outData; 298 } 299 300 /** 301 * Returns a short array of data elements from the specified rectangular 302 * region for the specified band. 303 * An ArrayIndexOutOfBounds exception will be thrown at runtime 304 * if the pixel coordinates are out of bounds. 305 * <pre> 306 * short[] bandData = Raster.getShortData(x, y, w, h, null); 307 * // To find the data element at location (x2, y2) 308 * short bandElement = bandData[((y2-y)*w + (x2-x))]; 309 * </pre> 310 * @param x The X coordinate of the upper left pixel location. 311 * @param y The Y coordinate of the upper left pixel location. 312 * @param w Width of the pixel rectangle. 313 * @param h Height of the pixel rectangle. 314 * @param band The band to return. 315 * @param outData If non-null, data elements for all bands 316 * at the specified location are returned in this array. 317 * @return Data array with data elements for all bands. 318 */ getShortData(int x, int y, int w, int h, int band, short[] outData)319 public short[] getShortData(int x, int y, int w, int h, 320 int band, short[] outData) { 321 // Bounds check for 'band' will be performed automatically 322 if ((x < this.minX) || (y < this.minY) || 323 (x + w > this.maxX) || (y + h > this.maxY)) { 324 throw new ArrayIndexOutOfBoundsException 325 ("Coordinate out of bounds!"); 326 } 327 if (outData == null) { 328 outData = new short[scanlineStride*h]; 329 } 330 int yoff = (y-minY)*scanlineStride + (x-minX) + dataOffsets[band]; 331 332 if (scanlineStride == w) { 333 System.arraycopy(data[band], yoff, outData, 0, w*h); 334 } else { 335 int off = 0; 336 for (int ystart=0; ystart < h; ystart++, yoff += scanlineStride) { 337 System.arraycopy(data[band], yoff, outData, off, w); 338 off += w; 339 } 340 } 341 342 return outData; 343 } 344 345 /** 346 * Returns a short array of data elements from the specified rectangular 347 * region. 348 * An ArrayIndexOutOfBounds exception will be thrown at runtime 349 * if the pixel coordinates are out of bounds. 350 * <pre> 351 * short[] bandData = Raster.getShortData(x, y, w, h, null); 352 * int numDataElements = Raster.getnumDataElements(); 353 * short[] pixel = new short[numDataElements]; 354 * // To find a data element at location (x2, y2) 355 * System.arraycopy(bandData, ((y2-y)*w + (x2-x))*numDataElements, 356 * pixel, 0, numDataElements); 357 * </pre> 358 * @param x The X coordinate of the upper left pixel location. 359 * @param y The Y coordinate of the upper left pixel location. 360 * @param w Width of the pixel rectangle. 361 * @param h Height of the pixel rectangle. 362 * @param outData If non-null, data elements for all bands 363 * at the specified location are returned in this array. 364 * @return Data array with data elements for all bands. 365 */ getShortData(int x, int y, int w, int h, short[] outData)366 public short[] getShortData(int x, int y, int w, int h, 367 short[] outData) { 368 if ((x < this.minX) || (y < this.minY) || 369 (x + w > this.maxX) || (y + h > this.maxY)) { 370 throw new ArrayIndexOutOfBoundsException 371 ("Coordinate out of bounds!"); 372 } 373 if (outData == null) { 374 outData = new short[numDataElements*scanlineStride*h]; 375 } 376 int yoff = (y-minY)*scanlineStride + (x-minX); 377 378 for (int c = 0; c < numDataElements; c++) { 379 int off = c; 380 short[] bank = data[c]; 381 int dataOffset = dataOffsets[c]; 382 383 int yoff2 = yoff; 384 for (int ystart=0; ystart < h; ystart++, yoff2 += scanlineStride) { 385 int xoff = dataOffset + yoff2; 386 for (int xstart=0; xstart < w; xstart++) { 387 outData[off] = bank[xoff++]; 388 off += numDataElements; 389 } 390 } 391 } 392 393 return outData; 394 } 395 396 /** 397 * Stores the data element for all bands at the specified location. 398 * An ArrayIndexOutOfBounds exception will be thrown at runtime 399 * if the pixel coordinate is out of bounds. 400 * A ClassCastException will be thrown if the input object is non null 401 * and references anything other than an array of transferType. 402 * @param x The X coordinate of the pixel location. 403 * @param y The Y coordinate of the pixel location. 404 * @param obj An object reference to an array of type defined by 405 * getTransferType() and length getNumDataElements() 406 * containing the pixel data to place at x,y. 407 */ setDataElements(int x, int y, Object obj)408 public void setDataElements(int x, int y, Object obj) { 409 if ((x < this.minX) || (y < this.minY) || 410 (x >= this.maxX) || (y >= this.maxY)) { 411 throw new ArrayIndexOutOfBoundsException 412 ("Coordinate out of bounds!"); 413 } 414 short[] inData = (short[])obj; 415 int off = (y-minY)*scanlineStride + (x-minX); 416 for (int i = 0; i < numDataElements; i++) { 417 data[i][dataOffsets[i] + off] = inData[i]; 418 } 419 420 markDirty(); 421 } 422 423 /** 424 * Stores the Raster data at the specified location. 425 * An ArrayIndexOutOfBounds exception will be thrown at runtime 426 * if the pixel coordinates are out of bounds. 427 * @param x The X coordinate of the pixel location. 428 * @param y The Y coordinate of the pixel location. 429 * @param inRaster Raster of data to place at x,y location. 430 */ setDataElements(int x, int y, Raster inRaster)431 public void setDataElements(int x, int y, Raster inRaster) { 432 int dstOffX = x + inRaster.getMinX(); 433 int dstOffY = y + inRaster.getMinY(); 434 int width = inRaster.getWidth(); 435 int height = inRaster.getHeight(); 436 if ((dstOffX < this.minX) || (dstOffY < this.minY) || 437 (dstOffX + width > this.maxX) || (dstOffY + height > this.maxY)) { 438 throw new ArrayIndexOutOfBoundsException 439 ("Coordinate out of bounds!"); 440 } 441 442 setDataElements(dstOffX, dstOffY, width, height, inRaster); 443 } 444 445 /** 446 * Stores the Raster data at the specified location. 447 * @param dstX The absolute X coordinate of the destination pixel 448 * that will receive a copy of the upper-left pixel of the 449 * inRaster 450 * @param dstY The absolute Y coordinate of the destination pixel 451 * that will receive a copy of the upper-left pixel of the 452 * inRaster 453 * @param width The number of pixels to store horizontally 454 * @param height The number of pixels to store vertically 455 * @param inRaster Raster of data to place at x,y location. 456 */ setDataElements(int dstX, int dstY, int width, int height, Raster inRaster)457 private void setDataElements(int dstX, int dstY, 458 int width, int height, 459 Raster inRaster) { 460 // Assume bounds checking has been performed previously 461 if (width <= 0 || height <= 0) { 462 return; 463 } 464 465 // Write inRaster (minX, minY) to (dstX, dstY) 466 467 int srcOffX = inRaster.getMinX(); 468 int srcOffY = inRaster.getMinY(); 469 Object tdata = null; 470 471 // // REMIND: Do something faster! 472 // if (inRaster instanceof ShortBandedRaster) { 473 // } 474 475 for (int startY=0; startY < height; startY++) { 476 // Grab one scanline at a time 477 tdata = inRaster.getDataElements(srcOffX, srcOffY+startY, 478 width, 1, tdata); 479 setDataElements(dstX, dstY + startY, width, 1, tdata); 480 } 481 } 482 483 /** 484 * Stores an array of data elements into the specified rectangular 485 * region. 486 * An ArrayIndexOutOfBounds exception will be thrown at runtime 487 * if the pixel coordinates are out of bounds. 488 * A ClassCastException will be thrown if the input object is non null 489 * and references anything other than an array of transferType. 490 * The data elements in the 491 * data array are assumed to be packed. That is, a data element 492 * for the nth band at location (x2, y2) would be found at: 493 * <pre> 494 * inData[((y2-y)*w + (x2-x))*numDataElements + n] 495 * </pre> 496 * @param x The X coordinate of the upper left pixel location. 497 * @param y The Y coordinate of the upper left pixel location. 498 * @param w Width of the pixel rectangle. 499 * @param h Height of the pixel rectangle. 500 * @param obj An object reference to an array of type defined by 501 * getTransferType() and length w*h*getNumDataElements() 502 * containing the pixel data to place between x,y and 503 * x+h, y+h. 504 */ setDataElements(int x, int y, int w, int h, Object obj)505 public void setDataElements(int x, int y, int w, int h, Object obj) { 506 if ((x < this.minX) || (y < this.minY) || 507 (x + w > this.maxX) || (y + h > this.maxY)) { 508 throw new ArrayIndexOutOfBoundsException 509 ("Coordinate out of bounds!"); 510 } 511 short[] inData = (short[])obj; 512 int yoff = (y-minY)*scanlineStride + (x-minX); 513 514 for (int c = 0; c < numDataElements; c++) { 515 int off = c; 516 short[] bank = data[c]; 517 int dataOffset = dataOffsets[c]; 518 519 int yoff2 = yoff; 520 for (int ystart=0; ystart < h; ystart++, yoff2 += scanlineStride) { 521 int xoff = dataOffset + yoff2; 522 for (int xstart=0; xstart < w; xstart++) { 523 bank[xoff++] = inData[off]; 524 off += numDataElements; 525 } 526 } 527 } 528 529 markDirty(); 530 } 531 532 /** 533 * Stores a short array of data elements into the specified 534 * rectangular region for the specified band. 535 * An ArrayIndexOutOfBounds exception will be thrown at runtime 536 * if the pixel coordinates are out of bounds. 537 * The data elements in the 538 * data array are assumed to be packed. That is, a data element 539 * at location (x2, y2) would be found at: 540 * <pre> 541 * inData[((y2-y)*w + (x2-x))] 542 * </pre> 543 * @param x The X coordinate of the upper left pixel location. 544 * @param y The Y coordinate of the upper left pixel location. 545 * @param w Width of the pixel rectangle. 546 * @param h Height of the pixel rectangle. 547 * @param band The band to set. 548 * @param inData The data elements to be stored. 549 */ putShortData(int x, int y, int w, int h, int band, short[] inData)550 public void putShortData(int x, int y, int w, int h, 551 int band, short[] inData) { 552 // Bounds check for 'band' will be performed automatically 553 if ((x < this.minX) || (y < this.minY) || 554 (x + w > this.maxX) || (y + h > this.maxY)) { 555 throw new ArrayIndexOutOfBoundsException 556 ("Coordinate out of bounds!"); 557 } 558 int yoff = (y-minY)*scanlineStride + (x-minX) + dataOffsets[band]; 559 int xoff; 560 int off = 0; 561 int xstart; 562 int ystart; 563 564 if (scanlineStride == w) { 565 System.arraycopy(inData, 0, data[band], yoff, w*h); 566 } else { 567 for (ystart=0; ystart < h; ystart++, yoff += scanlineStride) { 568 System.arraycopy(inData, off, data[band], yoff, w); 569 off += w; 570 } 571 } 572 573 markDirty(); 574 } 575 576 /** 577 * Stores a short integer array of data elements into the specified 578 * rectangular region. 579 * An ArrayIndexOutOfBounds exception will be thrown at runtime 580 * if the pixel coordinates are out of bounds. 581 * The data elements in the 582 * data array are assumed to be packed. That is, a data element 583 * for the nth band at location (x2, y2) would be found at: 584 * <pre> 585 * inData[((y2-y)*w + (x2-x))*numDataElements + n] 586 * </pre> 587 * @param x The X coordinate of the upper left pixel location. 588 * @param y The Y coordinate of the upper left pixel location. 589 * @param w Width of the pixel rectangle. 590 * @param h Height of the pixel rectangle. 591 * @param inData The data elements to be stored. 592 */ putShortData(int x, int y, int w, int h, short[] inData)593 public void putShortData(int x, int y, int w, int h, short[] inData) { 594 if ((x < this.minX) || (y < this.minY) || 595 (x + w > this.maxX) || (y + h > this.maxY)) { 596 throw new ArrayIndexOutOfBoundsException 597 ("Coordinate out of bounds!"); 598 } 599 int yoff = (y-minY)*scanlineStride + (x-minX); 600 601 for (int c = 0; c < numDataElements; c++) { 602 int off = c; 603 short[] bank = data[c]; 604 int dataOffset = dataOffsets[c]; 605 606 int yoff2 = yoff; 607 for (int ystart=0; ystart < h; ystart++, yoff2 += scanlineStride) { 608 int xoff = dataOffset + yoff2; 609 for (int xstart=0; xstart < w; xstart++) { 610 bank[xoff++] = inData[off]; 611 off += numDataElements; 612 } 613 } 614 } 615 616 markDirty(); 617 } 618 619 /** 620 * Creates a Writable subRaster given a region of the Raster. The x and y 621 * coordinates specify the horizontal and vertical offsets 622 * from the upper-left corner of this Raster to the upper-left corner 623 * of the subRaster. A subset of the bands of the parent Raster may 624 * be specified. If this is null, then all the bands are present in the 625 * subRaster. A translation to the subRaster may also be specified. 626 * Note that the subRaster will reference the same 627 * DataBuffers as the parent Raster, but using different offsets. 628 * @param x X offset. 629 * @param y Y offset. 630 * @param width Width (in pixels) of the subraster. 631 * @param height Height (in pixels) of the subraster. 632 * @param x0 Translated X origin of the subraster. 633 * @param y0 Translated Y origin of the subraster. 634 * @param bandList Array of band indices. 635 * @exception RasterFormatException 636 * if the specified bounding box is outside of the parent Raster. 637 */ createWritableChild(int x, int y, int width, int height, int x0, int y0, int[] bandList)638 public WritableRaster createWritableChild(int x, int y, 639 int width, int height, 640 int x0, int y0, 641 int[] bandList) { 642 643 if (x < this.minX) { 644 throw new RasterFormatException("x lies outside raster"); 645 } 646 if (y < this.minY) { 647 throw new RasterFormatException("y lies outside raster"); 648 } 649 if ((x+width < x) || (x+width > this.minX + this.width)) { 650 throw new RasterFormatException("(x + width) is outside of Raster"); 651 } 652 if ((y+height < y) || (y+height > this.minY + this.height)) { 653 throw new RasterFormatException("(y + height) is outside of Raster"); 654 } 655 656 SampleModel sm; 657 658 if (bandList != null) 659 sm = sampleModel.createSubsetSampleModel(bandList); 660 else 661 sm = sampleModel; 662 663 int deltaX = x0 - x; 664 int deltaY = y0 - y; 665 666 return new ShortBandedRaster(sm, 667 (DataBufferUShort) dataBuffer, 668 new Rectangle(x0, y0, width, height), 669 new Point(sampleModelTranslateX+deltaX, 670 sampleModelTranslateY+deltaY), 671 this); 672 673 } 674 675 /** 676 * Creates a subraster given a region of the raster. The x and y 677 * coordinates specify the horizontal and vertical offsets 678 * from the upper-left corner of this raster to the upper-left corner 679 * of the subraster. A subset of the bands of the parent Raster may 680 * be specified. If this is null, then all the bands are present in the 681 * subRaster. A translation to the subRaster may also be specified. 682 * Note that the subraster will reference the same 683 * DataBuffers as the parent raster, but using different offsets. 684 * @param x X offset. 685 * @param y Y offset. 686 * @param width Width (in pixels) of the subraster. 687 * @param height Height (in pixels) of the subraster. 688 * @param x0 Translated X origin of the subraster. 689 * @param y0 Translated Y origin of the subraster. 690 * @param bandList Array of band indices. 691 * @exception RasterFormatException 692 * if the specified bounding box is outside of the parent raster. 693 */ createChild(int x, int y, int width, int height, int x0, int y0, int[] bandList)694 public Raster createChild (int x, int y, 695 int width, int height, 696 int x0, int y0, 697 int[] bandList) { 698 return createWritableChild(x, y, width, height, x0, y0, bandList); 699 } 700 701 /** 702 * Creates a Raster with the same layout but using a different 703 * width and height, and with new zeroed data arrays. 704 */ createCompatibleWritableRaster(int w, int h)705 public WritableRaster createCompatibleWritableRaster(int w, int h) { 706 if (w <= 0 || h <=0) { 707 throw new RasterFormatException("negative "+ 708 ((w <= 0) ? "width" : "height")); 709 } 710 711 SampleModel sm = sampleModel.createCompatibleSampleModel(w,h); 712 713 return new ShortBandedRaster(sm, new Point(0,0)); 714 } 715 716 /** 717 * Creates a Raster with the same layout and the same 718 * width and height, and with new zeroed data arrays. If 719 * the Raster is a subRaster, this will call 720 * createCompatibleRaster(width, height). 721 */ createCompatibleWritableRaster()722 public WritableRaster createCompatibleWritableRaster() { 723 return createCompatibleWritableRaster(width,height); 724 } 725 726 /** 727 * Verify that the layout parameters are consistent with the data. 728 * Verifies whether the data buffer has enough data for the raster, 729 * taking into account offsets, after ensuring all offsets are >=0. 730 * @throws RasterFormatException if a problem is detected. 731 */ verify()732 private void verify() { 733 734 /* Need to re-verify the dimensions since a sample model may be 735 * specified to the constructor 736 */ 737 if (width <= 0 || height <= 0 || 738 height > (Integer.MAX_VALUE / width)) 739 { 740 throw new RasterFormatException("Invalid raster dimension"); 741 } 742 743 if (scanlineStride < 0 || 744 scanlineStride > (Integer.MAX_VALUE / height)) 745 { 746 // integer overflow 747 throw new RasterFormatException("Incorrect scanline stride: " 748 + scanlineStride); 749 } 750 751 if ((long)minX - sampleModelTranslateX < 0 || 752 (long)minY - sampleModelTranslateY < 0) { 753 754 throw new RasterFormatException("Incorrect origin/translate: (" + 755 minX + ", " + minY + ") / (" + 756 sampleModelTranslateX + ", " + sampleModelTranslateY + ")"); 757 } 758 759 if (height > 1 || minY - sampleModelTranslateY > 0) { 760 // buffer should contain at least one scanline 761 for (int i = 0; i < data.length; i++) { 762 if (scanlineStride > data[i].length) { 763 throw new RasterFormatException("Incorrect scanline stride: " 764 + scanlineStride); 765 } 766 } 767 } 768 769 // Make sure data for Raster is in a legal range 770 for (int i=0; i < dataOffsets.length; i++) { 771 if (dataOffsets[i] < 0) { 772 throw new RasterFormatException("Data offsets for band "+i+ 773 "("+dataOffsets[i]+ 774 ") must be >= 0"); 775 } 776 } 777 778 int lastScanOffset = (height - 1) * scanlineStride; 779 if ((width - 1) > (Integer.MAX_VALUE - lastScanOffset)) { 780 throw new RasterFormatException("Invalid raster dimension"); 781 } 782 int lastPixelOffset = lastScanOffset + (width - 1); 783 784 int maxIndex = 0; 785 int index; 786 787 for (int i=0; i < numDataElements; i++) { 788 if (dataOffsets[i] > (Integer.MAX_VALUE - lastPixelOffset)) { 789 throw new RasterFormatException("Invalid raster dimension"); 790 } 791 index = lastPixelOffset + dataOffsets[i]; 792 if (index > maxIndex) { 793 maxIndex = index; 794 } 795 } 796 for (int i=0; i < numDataElements; i++) { 797 if (data[i].length <= maxIndex) { 798 throw new RasterFormatException("Data array too small " + 799 "(should be > "+ maxIndex+" )"); 800 } 801 } 802 } 803 toString()804 public String toString() { 805 return new String ("ShortBandedRaster: width = "+width+" height = " 806 + height 807 +" #numBands " + numBands 808 +" #dataElements "+numDataElements); 809 810 } 811 812 } 813