1 /* 2 * Copyright (c) 1998, 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.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 IntegerInterleavedRaster extends IntegerComponentRaster { 53 54 /** A cached copy of minX + width for use in bounds checks. */ 55 private int maxX; 56 57 /** A cached copy of minY + height for use in bounds checks. */ 58 private int maxY; 59 60 /** 61 * Constructs a IntegerInterleavedRaster with the given SampleModel. 62 * The Raster's upper left corner is origin and it is the same 63 * size as the SampleModel. A DataBuffer large enough to describe the 64 * Raster is automatically created. SampleModel must be of type 65 * SinglePixelPackedSampleModel. 66 * @param sampleModel The SampleModel that specifies the layout. 67 * @param origin The Point that specified the origin. 68 */ 69 public IntegerInterleavedRaster(SampleModel sampleModel, 70 Point origin) { 71 this(sampleModel, 72 (DataBufferInt)sampleModel.createDataBuffer(), 73 new Rectangle(origin.x, 74 origin.y, 75 sampleModel.getWidth(), 76 sampleModel.getHeight()), 77 origin, 78 null); 79 } 80 81 /** 82 * Constructs a IntegerInterleavedRaster with the given SampleModel 83 * and DataBuffer. The Raster's upper left corner is origin and 84 * it is the same sizes the SampleModel. The DataBuffer is not 85 * initialized and must be a DataBufferInt compatible with SampleModel. 86 * SampleModel must be of type SinglePixelPackedSampleModel. 87 * @param sampleModel The SampleModel that specifies the layout. 88 * @param dataBuffer The DataBufferInt that contains the image data. 89 * @param origin The Point that specifies the origin. 90 */ 91 public IntegerInterleavedRaster(SampleModel sampleModel, 92 DataBufferInt dataBuffer, 93 Point origin) { 94 this(sampleModel, 95 dataBuffer, 96 new Rectangle(origin.x, 97 origin.y, 98 sampleModel.getWidth(), 99 sampleModel.getHeight()), 100 origin, 101 null); 102 } 103 104 /** 105 * Constructs a IntegerInterleavedRaster with the given SampleModel, 106 * DataBuffer, and parent. DataBuffer must be a DataBufferInt and 107 * SampleModel must be of type SinglePixelPackedSampleModel. 108 * When translated into the base Raster's 109 * coordinate system, aRegion must be contained by the base Raster. 110 * Origin is the coodinate in the new Raster's coordinate system of 111 * the origin of the base Raster. (The base Raster is the Raster's 112 * ancestor which has no parent.) 113 * 114 * Note that this constructor should generally be called by other 115 * constructors or create methods, it should not be used directly. 116 * @param sampleModel The SampleModel that specifies the layout. 117 * @param dataBuffer The DataBufferInt that contains the image data. 118 * @param aRegion The Rectangle that specifies the image area. 119 * @param origin The Point that specifies the origin. 120 * @param parent The parent (if any) of this raster. 121 */ 122 public IntegerInterleavedRaster(SampleModel sampleModel, 123 DataBufferInt dataBuffer, 124 Rectangle aRegion, 125 Point origin, 126 IntegerInterleavedRaster parent) { 127 super(sampleModel,dataBuffer,aRegion,origin,parent); 128 this.maxX = minX + width; 129 this.maxY = minY + height; 130 131 this.data = stealData(dataBuffer, 0); 132 133 if (sampleModel instanceof SinglePixelPackedSampleModel) { 134 SinglePixelPackedSampleModel sppsm = 135 (SinglePixelPackedSampleModel)sampleModel; 136 this.scanlineStride = sppsm.getScanlineStride(); 137 this.pixelStride = 1; 138 this.dataOffsets = new int[1]; 139 this.dataOffsets[0] = dataBuffer.getOffset(); 140 this.bandOffset = this.dataOffsets[0]; 141 int xOffset = aRegion.x - origin.x; 142 int yOffset = aRegion.y - origin.y; 143 dataOffsets[0] += xOffset+yOffset*scanlineStride; 144 this.numDataElems = sppsm.getNumDataElements(); 145 } else { 146 throw new RasterFormatException("IntegerInterleavedRasters must have"+ 147 " SinglePixelPackedSampleModel"); 148 } 149 verify(); 150 } 151 152 153 /** 154 * Returns a copy of the data offsets array. For each band the data offset 155 * is the index into the band's data array, of the first sample of the 156 * band. 157 */ 158 public int[] getDataOffsets() { 159 return dataOffsets.clone(); 160 } 161 162 /** 163 * Returns data offset for the specified band. The data offset 164 * is the index into the data array in which the first sample 165 * of the first scanline is stored. 166 */ 167 public int getDataOffset(int band) { 168 return dataOffsets[band]; 169 } 170 171 172 /** 173 * Returns the scanline stride -- the number of data array elements between 174 * a given sample and the sample in the same column of the next row. 175 */ 176 public int getScanlineStride() { 177 return scanlineStride; 178 } 179 180 /** 181 * Returns pixel stride -- the number of data array elements between two 182 * samples for the same band on the same scanline. 183 */ 184 public int getPixelStride() { 185 return pixelStride; 186 } 187 188 /** 189 * Returns a reference to the data array. 190 */ 191 public int[] getDataStorage() { 192 return data; 193 } 194 195 /** 196 * Returns the data elements for all bands at the specified 197 * location. 198 * An ArrayIndexOutOfBounds exception will be thrown at runtime 199 * if the pixel coordinate is out of bounds. 200 * A ClassCastException will be thrown if the input object is non null 201 * and references anything other than an array of transferType. 202 * @param x The X coordinate of the pixel location. 203 * @param y The Y coordinate of the pixel location. 204 * @param obj An object reference to an array of type defined by 205 * getTransferType() and length getNumDataElements(). 206 * If null an array of appropriate type and size will be 207 * allocated. 208 * @return An object reference to an array of type defined by 209 * getTransferType() with the request pixel data. 210 */ 211 public Object getDataElements(int x, int y, Object obj) { 212 if ((x < this.minX) || (y < this.minY) || 213 (x >= this.maxX) || (y >= this.maxY)) { 214 throw new ArrayIndexOutOfBoundsException 215 ("Coordinate out of bounds!"); 216 } 217 int outData[]; 218 if (obj == null) { 219 outData = new int[1]; 220 } else { 221 outData = (int[])obj; 222 } 223 int off = (y-minY)*scanlineStride + (x-minX) + dataOffsets[0]; 224 outData[0] = data[off]; 225 226 return outData; 227 } 228 229 230 /** 231 * Returns an array of data elements from the specified rectangular 232 * region. 233 * An ArrayIndexOutOfBounds exception will be thrown at runtime 234 * if the pixel coordinates are out of bounds. 235 * A ClassCastException will be thrown if the input object is non null 236 * and references anything other than an array of transferType. 237 <pre> 238 * int[] bandData = (int[])raster.getDataElements(x, y, w, h, null); 239 * int numDataElements = raster.getNumDataElements(); 240 * int[] pixel = new int[numDataElements]; 241 * // To find a data element at location (x2, y2) 242 * System.arraycopy(bandData, ((y2-y)*w + (x2-x))*numDataElements, 243 * pixel, 0, numDataElements); 244 * </pre> 245 * @param x The X coordinate of the upper left pixel location. 246 * @param y The Y coordinate of the upper left pixel location. 247 * @param w Width of the pixel rectangle. 248 * @param h Height of the pixel rectangle. 249 * @param obj An object reference to an array of type defined by 250 * getTransferType() and length w*h*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, int w, int h, Object obj) { 257 if ((x < this.minX) || (y < this.minY) || 258 (x + w > this.maxX) || (y + h > this.maxY)) { 259 throw new ArrayIndexOutOfBoundsException 260 ("Coordinate out of bounds!"); 261 } 262 int outData[]; 263 if (obj instanceof int[]) { 264 outData = (int[])obj; 265 } else { 266 outData = new int[w*h]; 267 } 268 int yoff = (y-minY)*scanlineStride + (x-minX) + dataOffsets[0]; 269 int off = 0; 270 271 for (int ystart = 0; ystart < h; ystart++) { 272 System.arraycopy(data, yoff, outData, off, w); 273 off += w; 274 yoff += scanlineStride; 275 } 276 277 return outData; 278 } 279 280 281 /** 282 * Stores the data elements for all bands at the specified location. 283 * An ArrayIndexOutOfBounds exception will be thrown at runtime 284 * if the pixel coordinate is out of bounds. 285 * A ClassCastException will be thrown if the input object is non null 286 * and references anything other than an array of transferType. 287 * @param x The X coordinate of the pixel location. 288 * @param y The Y coordinate of the pixel location. 289 * @param obj An object reference to an array of type defined by 290 * getTransferType() and length getNumDataElements() 291 * containing the pixel data to place at x,y. 292 */ 293 public void setDataElements(int x, int y, Object obj) { 294 if ((x < this.minX) || (y < this.minY) || 295 (x >= this.maxX) || (y >= this.maxY)) { 296 throw new ArrayIndexOutOfBoundsException 297 ("Coordinate out of bounds!"); 298 } 299 int inData[] = (int[])obj; 300 301 int off = (y-minY)*scanlineStride + (x-minX) + dataOffsets[0]; 302 303 data[off] = inData[0]; 304 305 markDirty(); 306 } 307 308 309 /** 310 * Stores the Raster data at the specified location. 311 * The transferType of the inputRaster must match this raster. 312 * An ArrayIndexOutOfBoundsException will be thrown at runtime 313 * if the pixel coordinates are out of bounds. 314 * @param x The X coordinate of the pixel location. 315 * @param y The Y coordinate of the pixel location. 316 * @param inRaster Raster of data to place at x,y location. 317 */ 318 public void setDataElements(int x, int y, Raster inRaster) { 319 int dstOffX = x + inRaster.getMinX(); 320 int dstOffY = y + inRaster.getMinY(); 321 int width = inRaster.getWidth(); 322 int height = inRaster.getHeight(); 323 if ((dstOffX < this.minX) || (dstOffY < this.minY) || 324 (dstOffX + width > this.maxX) || (dstOffY + height > this.maxY)) { 325 throw new ArrayIndexOutOfBoundsException 326 ("Coordinate out of bounds!"); 327 } 328 329 setDataElements(dstOffX, dstOffY, width, height, inRaster); 330 } 331 332 /** 333 * Stores the Raster data at the specified location. 334 * @param dstX The absolute X coordinate of the destination pixel 335 * that will receive a copy of the upper-left pixel of the 336 * inRaster 337 * @param dstY The absolute Y coordinate of the destination pixel 338 * that will receive a copy of the upper-left pixel of the 339 * inRaster 340 * @param width The number of pixels to store horizontally 341 * @param height The number of pixels to store vertically 342 * @param inRaster Raster of data to place at x,y location. 343 */ 344 private void setDataElements(int dstX, int dstY, 345 int width, int height, 346 Raster inRaster) { 347 // Assume bounds checking has been performed previously 348 if (width <= 0 || height <= 0) { 349 return; 350 } 351 352 // Write inRaster (minX, minY) to (dstX, dstY) 353 354 int srcOffX = inRaster.getMinX(); 355 int srcOffY = inRaster.getMinY(); 356 int tdata[] = null; 357 358 if (inRaster instanceof IntegerInterleavedRaster) { 359 IntegerInterleavedRaster ict = (IntegerInterleavedRaster) inRaster; 360 361 // Extract the raster parameters 362 tdata = ict.getDataStorage(); 363 int tss = ict.getScanlineStride(); 364 int toff = ict.getDataOffset(0); 365 366 int srcOffset = toff; 367 int dstOffset = dataOffsets[0]+(dstY-minY)*scanlineStride+ 368 (dstX-minX); 369 370 371 // Fastest case. We can copy scanlines 372 // Loop through all of the scanlines and copy the data 373 for (int startY=0; startY < height; startY++) { 374 System.arraycopy(tdata, srcOffset, data, dstOffset, width); 375 srcOffset += tss; 376 dstOffset += scanlineStride; 377 } 378 markDirty(); 379 return; 380 } 381 382 Object odata = null; 383 for (int startY=0; startY < height; startY++) { 384 // Grab one scanline at a time 385 odata = inRaster.getDataElements(srcOffX, srcOffY+startY, 386 width, 1, odata); 387 setDataElements(dstX, dstY+startY, width, 1, odata); 388 } 389 } 390 391 /** 392 * Stores an array of data elements into the specified rectangular 393 * region. 394 * An ArrayIndexOutOfBounds exception will be thrown at runtime 395 * if the pixel coordinates are out of bounds. 396 * A ClassCastException will be thrown if the input object is non null 397 * and references anything other than an array of transferType. 398 * The data elements in the 399 * data array are assumed to be packed. That is, a data element 400 * for the nth band at location (x2, y2) would be found at: 401 * <pre> 402 * inData[((y2-y)*w + (x2-x))*numDataElements + n] 403 * </pre> 404 * @param x The X coordinate of the upper left pixel location. 405 * @param y The Y coordinate of the upper left pixel location. 406 * @param w Width of the pixel rectangle. 407 * @param h Height of the pixel rectangle. 408 * @param obj An object reference to an array of type defined by 409 * getTransferType() and length w*h*getNumDataElements() 410 * containing the pixel data to place between x,y and 411 * x+h, y+h. 412 */ 413 public void setDataElements(int x, int y, int w, int h, Object obj) { 414 if ((x < this.minX) || (y < this.minY) || 415 (x + w > this.maxX) || (y + h > this.maxY)) { 416 throw new ArrayIndexOutOfBoundsException 417 ("Coordinate out of bounds!"); 418 } 419 int inData[] = (int[])obj; 420 int yoff = (y-minY)*scanlineStride + (x-minX) + dataOffsets[0]; 421 int off = 0; 422 423 for (int ystart = 0; ystart < h; ystart++) { 424 System.arraycopy(inData, off, data, yoff, w); 425 off += w; 426 yoff += scanlineStride; 427 } 428 429 markDirty(); 430 } 431 432 /** 433 * Creates a subraster given a region of the raster. The x and y 434 * coordinates specify the horizontal and vertical offsets 435 * from the upper-left corner of this raster to the upper-left corner 436 * of the subraster. A subset of the bands of the parent Raster may 437 * be specified. If this is null, then all the bands are present in the 438 * subRaster. A translation to the subRaster may also be specified. 439 * Note that the subraster will reference the same 440 * DataBuffer as the parent raster, but using different offsets. 441 * @param x X offset. 442 * @param y Y offset. 443 * @param width Width (in pixels) of the subraster. 444 * @param height Height (in pixels) of the subraster. 445 * @param x0 Translated X origin of the subraster. 446 * @param y0 Translated Y origin of the subraster. 447 * @param bandList Array of band indices. 448 * @exception RasterFormatException 449 * if the specified bounding box is outside of the parent raster. 450 */ 451 public WritableRaster createWritableChild (int x, int y, 452 int width, int height, 453 int x0, int y0, 454 int bandList[]) { 455 if (x < this.minX) { 456 throw new RasterFormatException("x lies outside raster"); 457 } 458 if (y < this.minY) { 459 throw new RasterFormatException("y lies outside raster"); 460 } 461 if ((x+width < x) || (x+width > this.minX + this.width)) { 462 throw new RasterFormatException("(x + width) is outside raster"); 463 } 464 if ((y+height < y) || (y+height > this.minY + this.height)) { 465 throw new RasterFormatException("(y + height) is outside raster"); 466 } 467 468 SampleModel sm; 469 470 if (bandList != null) 471 sm = sampleModel.createSubsetSampleModel(bandList); 472 else 473 sm = sampleModel; 474 475 int deltaX = x0 - x; 476 int deltaY = y0 - y; 477 478 return new IntegerInterleavedRaster(sm, 479 (DataBufferInt)dataBuffer, 480 new Rectangle(x0,y0,width,height), 481 new Point(sampleModelTranslateX+deltaX, 482 sampleModelTranslateY+deltaY), 483 this); 484 } 485 486 487 /** 488 * Creates a subraster given a region of the raster. The x and y 489 * coordinates specify the horizontal and vertical offsets 490 * from the upper-left corner of this raster to the upper-left corner 491 * of the subraster. A subset of the bands of the parent raster may 492 * be specified. If this is null, then all the bands are present in the 493 * subRaster. Note that the subraster will reference the same 494 * DataBuffer as the parent raster, but using different offsets. 495 * @param x X offset. 496 * @param y Y offset. 497 * @param width Width (in pixels) of the subraster. 498 * @param height Height (in pixels) of the subraster. 499 * @param x0 Translated X origin of the subRaster. 500 * @param y0 Translated Y origin of the subRaster. 501 * @param bandList Array of band indices. 502 * @exception RasterFormatException 503 * if the specified bounding box is outside of the parent raster. 504 */ 505 public Raster createChild (int x, int y, 506 int width, int height, 507 int x0, int y0, 508 int bandList[]) { 509 return createWritableChild(x, y, width, height, x0, y0, bandList); 510 } 511 512 513 /** 514 * Creates a raster with the same band layout but using a different 515 * width and height, and with new zeroed data arrays. 516 */ 517 public WritableRaster createCompatibleWritableRaster(int w, int h) { 518 if (w <= 0 || h <=0) { 519 throw new RasterFormatException("negative "+ 520 ((w <= 0) ? "width" : "height")); 521 } 522 523 SampleModel sm = sampleModel.createCompatibleSampleModel(w,h); 524 525 return new IntegerInterleavedRaster(sm, new Point(0,0)); 526 } 527 528 /** 529 * Creates a raster with the same data layout and the same 530 * width and height, and with new zeroed data arrays. If 531 * the raster is a subraster, this will call 532 * createCompatibleRaster(width, height). 533 */ 534 public WritableRaster createCompatibleWritableRaster() { 535 return createCompatibleWritableRaster(width,height); 536 } 537 538 public String toString() { 539 return new String ("IntegerInterleavedRaster: width = "+width 540 +" height = " + height 541 +" #Bands = " + numBands 542 +" xOff = "+sampleModelTranslateX 543 +" yOff = "+sampleModelTranslateY 544 +" dataOffset[0] "+dataOffsets[0]); 545 } 546 547 // /** 548 // * For debugging... prints a region of a one-band IntegerInterleavedRaster 549 // */ 550 // public void print(int x, int y, int w, int h) { 551 // // REMIND: Only works for 1 band! 552 // System.out.println(this); 553 // int offset = dataOffsets[0] + y*scanlineStride + x*pixelStride; 554 // int off; 555 // for (int yoff=0; yoff < h; yoff++, offset += scanlineStride) { 556 // off = offset; 557 // System.out.print("Line "+(sampleModelTranslateY+y+yoff)+": "); 558 // for (int xoff = 0; xoff < w; xoff++, off+= pixelStride) { 559 // System.out.print(Integer.toHexString(data[off])+" "); 560 // } 561 // System.out.println(""); 562 // } 563 // } 564 565 }