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