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