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