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