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