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