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