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 28 import java.awt.Point; 29 import java.awt.Rectangle; 30 import java.awt.image.DataBuffer; 31 import java.awt.image.DataBufferByte; 32 import java.awt.image.MultiPixelPackedSampleModel; 33 import java.awt.image.Raster; 34 import java.awt.image.RasterFormatException; 35 import java.awt.image.SampleModel; 36 import java.awt.image.WritableRaster; 37 38 /** 39 * This class is useful for describing 1, 2, or 4 bit image data 40 * elements. This raster has one band whose pixels are packed 41 * together into individual bytes in a single byte array. This type 42 * of raster can be used with an IndexColorModel. This raster uses a 43 * MultiPixelPackedSampleModel. 44 * 45 */ 46 public class BytePackedRaster extends SunWritableRaster { 47 48 /** The data bit offset for each pixel. */ 49 int dataBitOffset; 50 51 /** Scanline stride of the image data contained in this Raster. */ 52 int scanlineStride; 53 54 /** 55 * The bit stride of a pixel, equal to the total number of bits 56 * required to store a pixel. 57 */ 58 int pixelBitStride; 59 60 /** The bit mask for extracting the pixel. */ 61 int bitMask; 62 63 /** The image data array. */ 64 byte[] data; 65 66 /** 8 minus the pixel bit stride. */ 67 int shiftOffset; 68 69 int type; 70 71 /** A cached copy of minX + width for use in bounds checks. */ 72 private int maxX; 73 74 /** A cached copy of minY + height for use in bounds checks. */ 75 private int maxY; 76 initIDs()77 private static native void initIDs(); 78 static { 79 /* ensure that the necessary native libraries are loaded */ NativeLibLoader.loadLibraries()80 NativeLibLoader.loadLibraries(); initIDs()81 initIDs(); 82 } 83 84 /** 85 * Constructs a BytePackedRaster with the given SampleModel. 86 * The Raster's upper left corner is origin and it is the same 87 * size as the SampleModel. A DataBuffer large enough to describe the 88 * Raster is automatically created. SampleModel must be of type 89 * MultiPixelPackedSampleModel. 90 * @param sampleModel The SampleModel that specifies the layout. 91 * @param origin The Point that specified the origin. 92 */ BytePackedRaster(SampleModel sampleModel, Point origin)93 public BytePackedRaster(SampleModel sampleModel, Point origin) { 94 this(sampleModel, 95 (DataBufferByte) sampleModel.createDataBuffer(), 96 new Rectangle(origin.x, 97 origin.y, 98 sampleModel.getWidth(), 99 sampleModel.getHeight()), 100 origin, 101 null); 102 } 103 104 /** 105 * Constructs a BytePackedRaster with the given SampleModel 106 * and DataBuffer. The Raster's upper left corner is origin and 107 * it is the same size as the SampleModel. The DataBuffer is not 108 * initialized and must be a DataBufferByte compatible with SampleModel. 109 * SampleModel must be of type MultiPixelPackedSampleModel. 110 * @param sampleModel The SampleModel that specifies the layout. 111 * @param dataBuffer The DataBufferByte that contains the image data. 112 * @param origin The Point that specifies the origin. 113 */ BytePackedRaster(SampleModel sampleModel, DataBufferByte dataBuffer, Point origin)114 public BytePackedRaster(SampleModel sampleModel, 115 DataBufferByte dataBuffer, 116 Point origin) 117 { 118 this(sampleModel, 119 dataBuffer, 120 new Rectangle(origin.x, 121 origin.y, 122 sampleModel.getWidth(), 123 sampleModel.getHeight()), 124 origin, 125 null); 126 } 127 128 /** 129 * Constructs a BytePackedRaster with the given SampleModel, 130 * DataBuffer, and parent. DataBuffer must be a DataBufferByte and 131 * SampleModel must be of type MultiPixelPackedSampleModel. 132 * When translated into the base Raster's 133 * coordinate system, aRegion must be contained by the base Raster. 134 * Origin is the coordinate in the new Raster's coordinate system of 135 * the origin of the base Raster. (The base Raster is the Raster's 136 * ancestor which has no parent.) 137 * 138 * Note that this constructor should generally be called by other 139 * constructors or create methods, it should not be used directly. 140 * @param sampleModel The SampleModel that specifies the layout. 141 * @param dataBuffer The DataBufferByte that contains the image data. 142 * @param aRegion The Rectangle that specifies the image area. 143 * @param origin The Point that specifies the origin. 144 * @param parent The parent (if any) of this raster. 145 * 146 * @exception RasterFormatException if the parameters do not conform 147 * to requirements of this Raster type. 148 */ BytePackedRaster(SampleModel sampleModel, DataBufferByte dataBuffer, Rectangle aRegion, Point origin, BytePackedRaster parent)149 public BytePackedRaster(SampleModel sampleModel, 150 DataBufferByte dataBuffer, 151 Rectangle aRegion, 152 Point origin, 153 BytePackedRaster parent) 154 { 155 super(sampleModel,dataBuffer,aRegion,origin, parent); 156 this.maxX = minX + width; 157 this.maxY = minY + height; 158 159 this.data = stealData(dataBuffer, 0); 160 if (dataBuffer.getNumBanks() != 1) { 161 throw new 162 RasterFormatException("DataBuffer for BytePackedRasters"+ 163 " must only have 1 bank."); 164 } 165 int dbOffset = dataBuffer.getOffset(); 166 167 if (sampleModel instanceof MultiPixelPackedSampleModel) { 168 MultiPixelPackedSampleModel mppsm = 169 (MultiPixelPackedSampleModel)sampleModel; 170 this.type = IntegerComponentRaster.TYPE_BYTE_BINARY_SAMPLES; 171 pixelBitStride = mppsm.getPixelBitStride(); 172 if (pixelBitStride != 1 && 173 pixelBitStride != 2 && 174 pixelBitStride != 4) { 175 throw new RasterFormatException 176 ("BytePackedRasters must have a bit depth of 1, 2, or 4"); 177 } 178 scanlineStride = mppsm.getScanlineStride(); 179 dataBitOffset = mppsm.getDataBitOffset() + dbOffset*8; 180 int xOffset = aRegion.x - origin.x; 181 int yOffset = aRegion.y - origin.y; 182 dataBitOffset += xOffset*pixelBitStride + yOffset*scanlineStride*8; 183 bitMask = (1 << pixelBitStride) -1; 184 shiftOffset = 8 - pixelBitStride; 185 } else { 186 throw new RasterFormatException("BytePackedRasters must have"+ 187 "MultiPixelPackedSampleModel"); 188 } 189 verify(false); 190 } 191 192 /** 193 * Returns the data bit offset for the Raster. The data 194 * bit offset is the bit index into the data array element 195 * corresponding to the first sample of the first scanline. 196 */ getDataBitOffset()197 public int getDataBitOffset() { 198 return dataBitOffset; 199 } 200 201 /** 202 * Returns the scanline stride -- the number of data array elements between 203 * a given sample and the sample in the same column 204 * of the next row. 205 */ getScanlineStride()206 public int getScanlineStride() { 207 return scanlineStride; 208 } 209 210 /** 211 * Returns pixel bit stride -- the number of bits between two 212 * samples on the same scanline. 213 */ getPixelBitStride()214 public int getPixelBitStride() { 215 return pixelBitStride; 216 } 217 218 /** 219 * Returns a reference to the entire data array. 220 */ getDataStorage()221 public byte[] getDataStorage() { 222 return data; 223 } 224 225 /** 226 * Returns the data element at the specified 227 * location. 228 * An ArrayIndexOutOfBounds exception will be thrown at runtime 229 * if the pixel coordinate is out of bounds. 230 * A ClassCastException will be thrown if the input object is non null 231 * and references anything other than an array of transferType. 232 * @param x The X coordinate of the pixel location. 233 * @param y The Y coordinate of the pixel location. 234 * @param obj An object reference to an array of type defined by 235 * getTransferType() and length getNumDataElements(). 236 * If null an array of appropriate type and size will be 237 * allocated. 238 * @return An object reference to an array of type defined by 239 * getTransferType() with the request pixel data. 240 */ getDataElements(int x, int y, Object obj)241 public Object getDataElements(int x, int y, Object obj) { 242 if ((x < this.minX) || (y < this.minY) || 243 (x >= this.maxX) || (y >= this.maxY)) { 244 throw new ArrayIndexOutOfBoundsException 245 ("Coordinate out of bounds!"); 246 } 247 byte[] outData; 248 if (obj == null) { 249 outData = new byte[numDataElements]; 250 } else { 251 outData = (byte[])obj; 252 } 253 int bitnum = dataBitOffset + (x-minX) * pixelBitStride; 254 // Fix 4184283 255 int element = data[(y-minY) * scanlineStride + (bitnum >> 3)] & 0xff; 256 int shift = shiftOffset - (bitnum & 7); 257 outData[0] = (byte)((element >> shift) & bitMask); 258 return outData; 259 } 260 261 /** 262 * Returns the pixel data for the specified rectangle of pixels in a 263 * primitive array of type TransferType. 264 * For image data supported by the Java 2D API, this 265 * will be one of DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT, or 266 * DataBuffer.TYPE_INT. Data may be returned in a packed format, 267 * thus increasing efficiency for data transfers. 268 * 269 * An ArrayIndexOutOfBoundsException may be thrown 270 * if the coordinates are not in bounds. 271 * A ClassCastException will be thrown if the input object is non null 272 * and references anything other than an array of TransferType. 273 * @see java.awt.image.SampleModel#getDataElements(int, int, int, int, Object, DataBuffer) 274 * @param x The X coordinate of the upper left pixel location. 275 * @param y The Y coordinate of the upper left pixel location. 276 * @param w Width of the pixel rectangle. 277 * @param h Height of the pixel rectangle. 278 * @param outData An object reference to an array of type defined by 279 * getTransferType() and length w*h*getNumDataElements(). 280 * If null, an array of appropriate type and size will be 281 * allocated. 282 * @return An object reference to an array of type defined by 283 * getTransferType() with the requested pixel data. 284 */ getDataElements(int x, int y, int w, int h, Object outData)285 public Object getDataElements(int x, int y, int w, int h, 286 Object outData) { 287 return getByteData(x, y, w, h, (byte[])outData); 288 } 289 290 /** 291 * Returns an array of data elements from the specified rectangular 292 * region. 293 * 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 * byte[] bandData = (byte[])raster.getPixelData(x, y, w, h, null); 300 * int pixel; 301 * // To find a data element at location (x2, y2) 302 * pixel = bandData[((y2-y)*w + (x2-x))]; 303 * </pre> 304 * @param x The X coordinate of the upper left pixel location. 305 * @param y The Y coordinate of the upper left pixel location. 306 * @param w Width of the pixel rectangle. 307 * @param h Height of the pixel rectangle. 308 * @param obj An object reference to an array of type defined by 309 * getTransferType() and length w*h*getNumDataElements(). 310 * If null an array of appropriate type and size will be 311 * allocated. 312 * @return An object reference to an array of type defined by 313 * getTransferType() with the request pixel data. 314 */ getPixelData(int x, int y, int w, int h, Object obj)315 public Object getPixelData(int x, int y, int w, int h, Object obj) { 316 if ((x < this.minX) || (y < this.minY) || 317 (x + w > this.maxX) || (y + h > this.maxY)) { 318 throw new ArrayIndexOutOfBoundsException 319 ("Coordinate out of bounds!"); 320 } 321 byte[] outData; 322 if (obj == null) { 323 outData = new byte[numDataElements*w*h]; 324 } else { 325 outData = (byte[])obj; 326 } 327 int pixbits = pixelBitStride; 328 int scanbit = dataBitOffset + (x-minX) * pixbits; 329 int index = (y-minY) * scanlineStride; 330 int outindex = 0; 331 byte[] data = this.data; 332 333 for (int j = 0; j < h; j++) { 334 int bitnum = scanbit; 335 for (int i = 0; i < w; i++) { 336 int shift = shiftOffset - (bitnum & 7); 337 outData[outindex++] = 338 (byte)(bitMask & (data[index + (bitnum >> 3)] >> shift)); 339 bitnum += pixbits; 340 } 341 index += scanlineStride; 342 } 343 return outData; 344 } 345 346 /** 347 * Returns a byte array containing the specified data elements 348 * from the data array. The band index will be ignored. 349 * An ArrayIndexOutOfBounds exception will be thrown at runtime 350 * if the pixel coordinates are out of bounds. 351 * <pre> 352 * byte[] byteData = getByteData(x, y, band, w, h, null); 353 * // To find a data element at location (x2, y2) 354 * byte element = byteData[(y2-y)*w + (x2-x)]; 355 * </pre> 356 * @param x The X coordinate of the upper left pixel location. 357 * @param y The Y coordinate of the upper left pixel location. 358 * @param w Width of the pixel rectangle. 359 * @param h Height of the pixel rectangle. 360 * @param band The band to return, is ignored. 361 * @param outData If non-null, data elements 362 * at the specified locations are returned in this array. 363 * @return Byte array with data elements. 364 */ getByteData(int x, int y, int w, int h, int band, byte[] outData)365 public byte[] getByteData(int x, int y, int w, int h, 366 int band, byte[] outData) { 367 return getByteData(x, y, w, h, outData); 368 } 369 370 /** 371 * Returns a byte array containing the specified data elements 372 * from the data array. 373 * An ArrayIndexOutOfBounds exception will be thrown at runtime 374 * if the pixel coordinates are out of bounds. 375 * <pre> 376 * byte[] byteData = raster.getByteData(x, y, w, h, null); 377 * byte pixel; 378 * // To find a data element at location (x2, y2) 379 * pixel = byteData[((y2-y)*w + (x2-x))]; 380 * </pre> 381 * @param x The X coordinate of the upper left pixel location. 382 * @param y The Y coordinate of the upper left pixel location. 383 * @param w Width of the pixel rectangle. 384 * @param h Height of the pixel rectangle. 385 * @param outData If non-null, data elements 386 * at the specified locations are returned in this array. 387 * @return Byte array with data elements. 388 */ getByteData(int x, int y, int w, int h, byte[] outData)389 public byte[] getByteData(int x, int y, int w, int h, byte[] outData) { 390 if ((x < this.minX) || (y < this.minY) || 391 (x + w > this.maxX) || (y + h > this.maxY)) { 392 throw new ArrayIndexOutOfBoundsException 393 ("Coordinate out of bounds!"); 394 } 395 if (outData == null) { 396 outData = new byte[w * h]; 397 } 398 int pixbits = pixelBitStride; 399 int scanbit = dataBitOffset + (x-minX) * pixbits; 400 int index = (y-minY) * scanlineStride; 401 int outindex = 0; 402 byte[] data = this.data; 403 404 for (int j = 0; j < h; j++) { 405 int bitnum = scanbit; 406 int element; 407 408 // Process initial portion of scanline 409 int i = 0; 410 while ((i < w) && ((bitnum & 7) != 0)) { 411 int shift = shiftOffset - (bitnum & 7); 412 outData[outindex++] = 413 (byte)(bitMask & (data[index + (bitnum >> 3)] >> shift)); 414 bitnum += pixbits; 415 i++; 416 } 417 418 // Process central portion of scanline 8 pixels at a time 419 int inIndex = index + (bitnum >> 3); 420 switch (pixbits) { 421 case 1: 422 for (; i < w - 7; i += 8) { 423 element = data[inIndex++]; 424 outData[outindex++] = (byte)((element >> 7) & 1); 425 outData[outindex++] = (byte)((element >> 6) & 1); 426 outData[outindex++] = (byte)((element >> 5) & 1); 427 outData[outindex++] = (byte)((element >> 4) & 1); 428 outData[outindex++] = (byte)((element >> 3) & 1); 429 outData[outindex++] = (byte)((element >> 2) & 1); 430 outData[outindex++] = (byte)((element >> 1) & 1); 431 outData[outindex++] = (byte)(element & 1); 432 bitnum += 8; 433 } 434 break; 435 436 case 2: 437 for (; i < w - 7; i += 8) { 438 element = data[inIndex++]; 439 outData[outindex++] = (byte)((element >> 6) & 3); 440 outData[outindex++] = (byte)((element >> 4) & 3); 441 outData[outindex++] = (byte)((element >> 2) & 3); 442 outData[outindex++] = (byte)(element & 3); 443 444 element = data[inIndex++]; 445 outData[outindex++] = (byte)((element >> 6) & 3); 446 outData[outindex++] = (byte)((element >> 4) & 3); 447 outData[outindex++] = (byte)((element >> 2) & 3); 448 outData[outindex++] = (byte)(element & 3); 449 450 bitnum += 16; 451 } 452 break; 453 454 case 4: 455 for (; i < w - 7; i += 8) { 456 element = data[inIndex++]; 457 outData[outindex++] = (byte)((element >> 4) & 0xf); 458 outData[outindex++] = (byte)(element & 0xf); 459 460 element = data[inIndex++]; 461 outData[outindex++] = (byte)((element >> 4) & 0xf); 462 outData[outindex++] = (byte)(element & 0xf); 463 464 element = data[inIndex++]; 465 outData[outindex++] = (byte)((element >> 4) & 0xf); 466 outData[outindex++] = (byte)(element & 0xf); 467 468 element = data[inIndex++]; 469 outData[outindex++] = (byte)((element >> 4) & 0xf); 470 outData[outindex++] = (byte)(element & 0xf); 471 472 bitnum += 32; 473 } 474 break; 475 } 476 477 // Process final portion of scanline 478 for (; i < w; i++) { 479 int shift = shiftOffset - (bitnum & 7); 480 outData[outindex++] = 481 (byte) (bitMask & (data[index + (bitnum >> 3)] >> shift)); 482 bitnum += pixbits; 483 } 484 485 index += scanlineStride; 486 } 487 488 return outData; 489 } 490 491 /** 492 * Stores the data elements at the specified location. 493 * An ArrayIndexOutOfBounds exception will be thrown at runtime 494 * if the pixel coordinate is out of bounds. 495 * A ClassCastException will be thrown if the input object is non null 496 * and references anything other than an array of transferType. 497 * @param x The X coordinate of the pixel location. 498 * @param y The Y coordinate of the pixel location. 499 * @param obj An object reference to an array of type defined by 500 * getTransferType() and length getNumDataElements() 501 * containing the pixel data to place at x,y. 502 */ setDataElements(int x, int y, Object obj)503 public void setDataElements(int x, int y, Object obj) { 504 if ((x < this.minX) || (y < this.minY) || 505 (x >= this.maxX) || (y >= this.maxY)) { 506 throw new ArrayIndexOutOfBoundsException 507 ("Coordinate out of bounds!"); 508 } 509 byte[] inData = (byte[])obj; 510 int bitnum = dataBitOffset + (x-minX) * pixelBitStride; 511 int index = (y-minY) * scanlineStride + (bitnum >> 3); 512 int shift = shiftOffset - (bitnum & 7); 513 514 byte element = data[index]; 515 element &= ~(bitMask << shift); 516 element |= (inData[0] & bitMask) << shift; 517 data[index] = element; 518 519 markDirty(); 520 } 521 522 /** 523 * Stores the Raster data at the specified location. 524 * An ArrayIndexOutOfBounds exception will be thrown at runtime 525 * if the pixel coordinates are out of bounds. 526 * @param x The X coordinate of the pixel location. 527 * @param y The Y coordinate of the pixel location. 528 * @param inRaster Raster of data to place at x,y location. 529 */ setDataElements(int x, int y, Raster inRaster)530 public void setDataElements(int x, int y, Raster inRaster) { 531 // Check if we can use fast code 532 if (!(inRaster instanceof BytePackedRaster) || 533 ((BytePackedRaster)inRaster).pixelBitStride != pixelBitStride) { 534 super.setDataElements(x, y, inRaster); 535 return; 536 } 537 538 int srcOffX = inRaster.getMinX(); 539 int srcOffY = inRaster.getMinY(); 540 int dstOffX = srcOffX + x; 541 int dstOffY = srcOffY + y; 542 int width = inRaster.getWidth(); 543 int height = inRaster.getHeight(); 544 if ((dstOffX < this.minX) || (dstOffY < this.minY) || 545 (dstOffX + width > this.maxX) || (dstOffY + height > this.maxY)) { 546 throw new ArrayIndexOutOfBoundsException 547 ("Coordinate out of bounds!"); 548 } 549 setDataElements(dstOffX, dstOffY, 550 srcOffX, srcOffY, 551 width, height, 552 (BytePackedRaster)inRaster); 553 } 554 555 /** 556 * Stores the Raster data at the specified location. 557 * @param dstX The absolute X coordinate of the destination pixel 558 * that will receive a copy of the upper-left pixel of the 559 * inRaster 560 * @param dstY The absolute Y coordinate of the destination pixel 561 * that will receive a copy of the upper-left pixel of the 562 * inRaster 563 * @param srcX The absolute X coordinate of the upper-left source 564 * pixel that will be copied into this Raster 565 * @param srcY The absolute Y coordinate of the upper-left source 566 * pixel that will be copied into this Raster 567 * @param width The number of pixels to store horizontally 568 * @param height The number of pixels to store vertically 569 * @param inRaster BytePackedRaster of data to place at x,y location. 570 */ setDataElements(int dstX, int dstY, int srcX, int srcY, int width, int height, BytePackedRaster inRaster)571 private void setDataElements(int dstX, int dstY, 572 int srcX, int srcY, 573 int width, int height, 574 BytePackedRaster inRaster) { 575 // Assume bounds checking has been performed previously 576 if (width <= 0 || height <= 0) { 577 return; 578 } 579 580 byte[] inData = inRaster.data; 581 byte[] outData = this.data; 582 583 int inscan = inRaster.scanlineStride; 584 int outscan = this.scanlineStride; 585 int inbit = inRaster.dataBitOffset + 586 8 * (srcY - inRaster.minY) * inscan + 587 (srcX - inRaster.minX) * inRaster.pixelBitStride; 588 int outbit = (this.dataBitOffset + 589 8 * (dstY - minY) * outscan + 590 (dstX - minX) * this.pixelBitStride); 591 int copybits = width * pixelBitStride; 592 593 // Check whether the same bit alignment is present in both 594 // Rasters; if so, we can copy whole bytes using 595 // System.arraycopy. If not, we must do a "funnel shift" 596 // where adjacent bytes contribute to each destination byte. 597 if ((inbit & 7) == (outbit & 7)) { 598 // copy is bit aligned 599 int bitpos = outbit & 7; 600 if (bitpos != 0) { 601 int bits = 8 - bitpos; 602 // Copy partial bytes on left 603 int inbyte = inbit >> 3; 604 int outbyte = outbit >> 3; 605 int mask = 0xff >> bitpos; 606 if (copybits < bits) { 607 // Fix bug 4399076: previously had '8 - copybits' instead 608 // of 'bits - copybits'. 609 // 610 // Prior to the this expression, 'mask' has its rightmost 611 // 'bits' bits set to '1'. We want it to have a total 612 // of 'copybits' bits set, therefore we want to introduce 613 // 'bits - copybits' zeroes on the right. 614 mask &= 0xff << (bits - copybits); 615 bits = copybits; 616 } 617 for (int j = 0; j < height; j++) { 618 int element = outData[outbyte]; 619 element &= ~mask; 620 element |= (inData[inbyte] & mask); 621 outData[outbyte] = (byte) element; 622 inbyte += inscan; 623 outbyte += outscan; 624 } 625 inbit += bits; 626 outbit += bits; 627 copybits -= bits; 628 } 629 if (copybits >= 8) { 630 // Copy whole bytes 631 int inbyte = inbit >> 3; 632 int outbyte = outbit >> 3; 633 int copybytes = copybits >> 3; 634 if (copybytes == inscan && inscan == outscan) { 635 System.arraycopy(inData, inbyte, 636 outData, outbyte, 637 inscan * height); 638 } else { 639 for (int j = 0; j < height; j++) { 640 System.arraycopy(inData, inbyte, 641 outData, outbyte, 642 copybytes); 643 inbyte += inscan; 644 outbyte += outscan; 645 } 646 } 647 648 int bits = copybytes*8; 649 inbit += bits; 650 outbit += bits; 651 copybits -= bits; 652 } 653 if (copybits > 0) { 654 // Copy partial bytes on right 655 int inbyte = inbit >> 3; 656 int outbyte = outbit >> 3; 657 int mask = (0xff00 >> copybits) & 0xff; 658 for (int j = 0; j < height; j++) { 659 int element = outData[outbyte]; 660 element &= ~mask; 661 element |= (inData[inbyte] & mask); 662 outData[outbyte] = (byte) element; 663 inbyte += inscan; 664 outbyte += outscan; 665 } 666 } 667 } else { 668 // Unaligned case, see RFE #4284166 669 // Note that the code in that RFE is not correct 670 671 // Insert bits into the first byte of the output 672 // if either the starting bit position is not zero or 673 // we are writing fewer than 8 bits in total 674 int bitpos = outbit & 7; 675 if (bitpos != 0 || copybits < 8) { 676 int bits = 8 - bitpos; 677 int inbyte = inbit >> 3; 678 int outbyte = outbit >> 3; 679 680 int lshift = inbit & 7; 681 int rshift = 8 - lshift; 682 int mask = 0xff >> bitpos; 683 if (copybits < bits) { 684 // Fix mask if we're only writing a partial byte 685 mask &= 0xff << (bits - copybits); 686 bits = copybits; 687 } 688 int lastByte = inData.length - 1; 689 for (int j = 0; j < height; j++) { 690 // Read two bytes from the source if possible 691 // Don't worry about going over a scanline boundary 692 // since any extra bits won't get used anyway 693 byte inData0 = inData[inbyte]; 694 byte inData1 = (byte)0; 695 if (inbyte < lastByte) { 696 inData1 = inData[inbyte + 1]; 697 } 698 699 // Insert the new bits into the output 700 int element = outData[outbyte]; 701 element &= ~mask; 702 element |= (((inData0 << lshift) | 703 ((inData1 & 0xff) >> rshift)) 704 >> bitpos) & mask; 705 outData[outbyte] = (byte)element; 706 inbyte += inscan; 707 outbyte += outscan; 708 } 709 710 inbit += bits; 711 outbit += bits; 712 copybits -= bits; 713 } 714 715 // Now we have outbit & 7 == 0 so we can write 716 // complete bytes for a while 717 718 // Make sure we have work to do in the central loop 719 // to avoid reading past the end of the scanline 720 if (copybits >= 8) { 721 int inbyte = inbit >> 3; 722 int outbyte = outbit >> 3; 723 int copybytes = copybits >> 3; 724 int lshift = inbit & 7; 725 int rshift = 8 - lshift; 726 727 for (int j = 0; j < height; j++) { 728 int ibyte = inbyte + j*inscan; 729 int obyte = outbyte + j*outscan; 730 731 int inData0 = inData[ibyte]; 732 // Combine adjacent bytes while 8 or more bits left 733 for (int i = 0; i < copybytes; i++) { 734 int inData1 = inData[ibyte + 1]; 735 int val = (inData0 << lshift) | 736 ((inData1 & 0xff) >> rshift); 737 outData[obyte] = (byte)val; 738 inData0 = inData1; 739 740 ++ibyte; 741 ++obyte; 742 } 743 } 744 745 int bits = copybytes*8; 746 inbit += bits; 747 outbit += bits; 748 copybits -= bits; 749 } 750 751 // Finish last byte 752 if (copybits > 0) { 753 int inbyte = inbit >> 3; 754 int outbyte = outbit >> 3; 755 int mask = (0xff00 >> copybits) & 0xff; 756 int lshift = inbit & 7; 757 int rshift = 8 - lshift; 758 759 int lastByte = inData.length - 1; 760 for (int j = 0; j < height; j++) { 761 byte inData0 = inData[inbyte]; 762 byte inData1 = (byte)0; 763 if (inbyte < lastByte) { 764 inData1 = inData[inbyte + 1]; 765 } 766 767 // Insert the new bits into the output 768 int element = outData[outbyte]; 769 element &= ~mask; 770 element |= ((inData0 << lshift) | 771 ((inData1 & 0xff) >> rshift)) & mask; 772 outData[outbyte] = (byte)element; 773 774 inbyte += inscan; 775 outbyte += outscan; 776 } 777 } 778 } 779 780 markDirty(); 781 } 782 783 /** 784 * Copies pixels from Raster srcRaster to this WritableRaster. 785 * For each (x, y) address in srcRaster, the corresponding pixel 786 * is copied to address (x+dx, y+dy) in this WritableRaster, 787 * unless (x+dx, y+dy) falls outside the bounds of this raster. 788 * srcRaster must have the same number of bands as this WritableRaster. 789 * The copy is a simple copy of source samples to the corresponding 790 * destination samples. For details, see 791 * {@link WritableRaster#setRect(Raster)}. 792 * 793 * @param dx The X translation factor from src space to dst space 794 * of the copy. 795 * @param dy The Y translation factor from src space to dst space 796 * of the copy. 797 * @param srcRaster The Raster from which to copy pixels. 798 */ setRect(int dx, int dy, Raster srcRaster)799 public void setRect(int dx, int dy, Raster srcRaster) { 800 // Check if we can use fast code 801 if (!(srcRaster instanceof BytePackedRaster) || 802 ((BytePackedRaster)srcRaster).pixelBitStride != pixelBitStride) { 803 super.setRect(dx, dy, srcRaster); 804 return; 805 } 806 807 int width = srcRaster.getWidth(); 808 int height = srcRaster.getHeight(); 809 int srcOffX = srcRaster.getMinX(); 810 int srcOffY = srcRaster.getMinY(); 811 int dstOffX = dx+srcOffX; 812 int dstOffY = dy+srcOffY; 813 814 // Clip to this raster 815 if (dstOffX < this.minX) { 816 int skipX = this.minX - dstOffX; 817 width -= skipX; 818 srcOffX += skipX; 819 dstOffX = this.minX; 820 } 821 if (dstOffY < this.minY) { 822 int skipY = this.minY - dstOffY; 823 height -= skipY; 824 srcOffY += skipY; 825 dstOffY = this.minY; 826 } 827 if (dstOffX+width > this.maxX) { 828 width = this.maxX - dstOffX; 829 } 830 if (dstOffY+height > this.maxY) { 831 height = this.maxY - dstOffY; 832 } 833 834 setDataElements(dstOffX, dstOffY, 835 srcOffX, srcOffY, 836 width, height, 837 (BytePackedRaster)srcRaster); 838 } 839 840 /** 841 * Stores an array of data elements into the specified rectangular 842 * region. 843 * An ArrayIndexOutOfBounds exception will be thrown at runtime 844 * if the pixel coordinates are out of bounds. 845 * A ClassCastException will be thrown if the input object is non null 846 * and references anything other than an array of transferType. 847 * The data elements in the 848 * data array are assumed to be packed. That is, a data element 849 * at location (x2, y2) would be found at: 850 * <pre> 851 * inData[((y2-y)*w + (x2-x))] 852 * </pre> 853 * @param x The X coordinate of the upper left pixel location. 854 * @param y The Y coordinate of the upper left pixel location. 855 * @param w Width of the pixel rectangle. 856 * @param h Height of the pixel rectangle. 857 * @param obj An object reference to an array of type defined by 858 * getTransferType() and length w*h*getNumDataElements() 859 * containing the pixel data to place between x,y and 860 * x+h, y+h. 861 */ setDataElements(int x, int y, int w, int h, Object obj)862 public void setDataElements(int x, int y, int w, int h, Object obj) { 863 putByteData(x, y, w, h, (byte[])obj); 864 } 865 866 /** 867 * Stores a byte array of data elements into the specified rectangular 868 * region. The band index will be ignored. 869 * An ArrayIndexOutOfBounds exception will be thrown at runtime 870 * if the pixel coordinates are out of bounds. 871 * The data elements in the 872 * data array are assumed to be packed. That is, a data element 873 * at location (x2, y2) would be found at: 874 * <pre> 875 * inData[((y2-y)*w + (x2-x))] 876 * </pre> 877 * @param x The X coordinate of the upper left pixel location. 878 * @param y The Y coordinate of the upper left pixel location. 879 * @param w Width of the pixel rectangle. 880 * @param h Height of the pixel rectangle. 881 * @param band The band to set, is ignored. 882 * @param inData The data elements to be stored. 883 */ putByteData(int x, int y, int w, int h, int band, byte[] inData)884 public void putByteData(int x, int y, int w, int h, 885 int band, byte[] inData) { 886 putByteData(x, y, w, h, inData); 887 } 888 889 /** 890 * Stores a byte array of data elements into the specified rectangular 891 * region. 892 * An ArrayIndexOutOfBounds exception will be thrown at runtime 893 * if the pixel coordinates are out of bounds. 894 * The data elements in the 895 * data array are assumed to be packed. That is, a data element 896 * at location (x2, y2) would be found at: 897 * <pre> 898 * inData[((y2-y)*w + (x2-x))] 899 * </pre> 900 * @param x The X coordinate of the upper left pixel location. 901 * @param y The Y coordinate of the upper left pixel location. 902 * @param w Width of the pixel rectangle. 903 * @param h Height of the pixel rectangle. 904 * @param inData The data elements to be stored. 905 */ putByteData(int x, int y, int w, int h, byte[] inData)906 public void putByteData(int x, int y, int w, int h, byte[] inData) { 907 if ((x < this.minX) || (y < this.minY) || 908 (x + w > this.maxX) || (y + h > this.maxY)) { 909 throw new ArrayIndexOutOfBoundsException 910 ("Coordinate out of bounds!"); 911 } 912 if (w == 0 || h == 0) { 913 return; 914 } 915 916 int pixbits = pixelBitStride; 917 int scanbit = dataBitOffset + (x - minX) * pixbits; 918 int index = (y - minY) * scanlineStride; 919 int outindex = 0; 920 byte[] data = this.data; 921 for (int j = 0; j < h; j++) { 922 int bitnum = scanbit; 923 int element; 924 925 // Process initial portion of scanline 926 int i = 0; 927 while ((i < w) && ((bitnum & 7) != 0)) { 928 int shift = shiftOffset - (bitnum & 7); 929 element = data[index + (bitnum >> 3)]; 930 element &= ~(bitMask << shift); 931 element |= (inData[outindex++] & bitMask) << shift; 932 data[index + (bitnum >> 3)] = (byte)element; 933 934 bitnum += pixbits; 935 i++; 936 } 937 938 // Process central portion of scanline 8 pixels at a time 939 int inIndex = index + (bitnum >> 3); 940 switch (pixbits) { 941 case 1: 942 for (; i < w - 7; i += 8) { 943 element = (inData[outindex++] & 1) << 7; 944 element |= (inData[outindex++] & 1) << 6; 945 element |= (inData[outindex++] & 1) << 5; 946 element |= (inData[outindex++] & 1) << 4; 947 element |= (inData[outindex++] & 1) << 3; 948 element |= (inData[outindex++] & 1) << 2; 949 element |= (inData[outindex++] & 1) << 1; 950 element |= (inData[outindex++] & 1); 951 952 data[inIndex++] = (byte)element; 953 954 bitnum += 8; 955 } 956 break; 957 958 case 2: 959 for (; i < w - 7; i += 8) { 960 element = (inData[outindex++] & 3) << 6; 961 element |= (inData[outindex++] & 3) << 4; 962 element |= (inData[outindex++] & 3) << 2; 963 element |= (inData[outindex++] & 3); 964 data[inIndex++] = (byte)element; 965 966 element = (inData[outindex++] & 3) << 6; 967 element |= (inData[outindex++] & 3) << 4; 968 element |= (inData[outindex++] & 3) << 2; 969 element |= (inData[outindex++] & 3); 970 data[inIndex++] = (byte)element; 971 972 bitnum += 16; 973 } 974 break; 975 976 case 4: 977 for (; i < w - 7; i += 8) { 978 element = (inData[outindex++] & 0xf) << 4; 979 element |= (inData[outindex++] & 0xf); 980 data[inIndex++] = (byte)element; 981 982 element = (inData[outindex++] & 0xf) << 4; 983 element |= (inData[outindex++] & 0xf); 984 data[inIndex++] = (byte)element; 985 986 element = (inData[outindex++] & 0xf) << 4; 987 element |= (inData[outindex++] & 0xf); 988 data[inIndex++] = (byte)element; 989 990 element = (inData[outindex++] & 0xf) << 4; 991 element |= (inData[outindex++] & 0xf); 992 data[inIndex++] = (byte)element; 993 994 bitnum += 32; 995 } 996 break; 997 } 998 999 // Process final portion of scanline 1000 for (; i < w; i++) { 1001 int shift = shiftOffset - (bitnum & 7); 1002 1003 element = data[index + (bitnum >> 3)]; 1004 element &= ~(bitMask << shift); 1005 element |= (inData[outindex++] & bitMask) << shift; 1006 data[index + (bitnum >> 3)] = (byte)element; 1007 1008 bitnum += pixbits; 1009 } 1010 1011 index += scanlineStride; 1012 } 1013 1014 markDirty(); 1015 } 1016 1017 /** 1018 * Returns an int array containing all samples for a rectangle of pixels, 1019 * one sample per array element. 1020 * An ArrayIndexOutOfBoundsException may be thrown 1021 * if the coordinates are not in bounds. 1022 * @param x, y the coordinates of the upper-left pixel location 1023 * @param w Width of the pixel rectangle 1024 * @param h Height of the pixel rectangle 1025 * @param iArray An optionally pre-allocated int array 1026 * @return the samples for the specified rectangle of pixels. 1027 */ getPixels(int x, int y, int w, int h, int[] iArray)1028 public int[] getPixels(int x, int y, int w, int h, int[] iArray) { 1029 if ((x < this.minX) || (y < this.minY) || 1030 (x + w > this.maxX) || (y + h > this.maxY)) { 1031 throw new ArrayIndexOutOfBoundsException 1032 ("Coordinate out of bounds!"); 1033 } 1034 if (iArray == null) { 1035 iArray = new int[w * h]; 1036 } 1037 int pixbits = pixelBitStride; 1038 int scanbit = dataBitOffset + (x-minX) * pixbits; 1039 int index = (y-minY) * scanlineStride; 1040 int outindex = 0; 1041 byte[] data = this.data; 1042 1043 for (int j = 0; j < h; j++) { 1044 int bitnum = scanbit; 1045 int element; 1046 1047 // Process initial portion of scanline 1048 int i = 0; 1049 while ((i < w) && ((bitnum & 7) != 0)) { 1050 int shift = shiftOffset - (bitnum & 7); 1051 iArray[outindex++] = 1052 bitMask & (data[index + (bitnum >> 3)] >> shift); 1053 bitnum += pixbits; 1054 i++; 1055 } 1056 1057 // Process central portion of scanline 8 pixels at a time 1058 int inIndex = index + (bitnum >> 3); 1059 switch (pixbits) { 1060 case 1: 1061 for (; i < w - 7; i += 8) { 1062 element = data[inIndex++]; 1063 iArray[outindex++] = (element >> 7) & 1; 1064 iArray[outindex++] = (element >> 6) & 1; 1065 iArray[outindex++] = (element >> 5) & 1; 1066 iArray[outindex++] = (element >> 4) & 1; 1067 iArray[outindex++] = (element >> 3) & 1; 1068 iArray[outindex++] = (element >> 2) & 1; 1069 iArray[outindex++] = (element >> 1) & 1; 1070 iArray[outindex++] = element & 1; 1071 bitnum += 8; 1072 } 1073 break; 1074 1075 case 2: 1076 for (; i < w - 7; i += 8) { 1077 element = data[inIndex++]; 1078 iArray[outindex++] = (element >> 6) & 3; 1079 iArray[outindex++] = (element >> 4) & 3; 1080 iArray[outindex++] = (element >> 2) & 3; 1081 iArray[outindex++] = element & 3; 1082 1083 element = data[inIndex++]; 1084 iArray[outindex++] = (element >> 6) & 3; 1085 iArray[outindex++] = (element >> 4) & 3; 1086 iArray[outindex++] = (element >> 2) & 3; 1087 iArray[outindex++] = element & 3; 1088 1089 bitnum += 16; 1090 } 1091 break; 1092 1093 case 4: 1094 for (; i < w - 7; i += 8) { 1095 element = data[inIndex++]; 1096 iArray[outindex++] = (element >> 4) & 0xf; 1097 iArray[outindex++] = element & 0xf; 1098 1099 element = data[inIndex++]; 1100 iArray[outindex++] = (element >> 4) & 0xf; 1101 iArray[outindex++] = element & 0xf; 1102 1103 element = data[inIndex++]; 1104 iArray[outindex++] = (element >> 4) & 0xf; 1105 iArray[outindex++] = element & 0xf; 1106 1107 element = data[inIndex++]; 1108 iArray[outindex++] = (element >> 4) & 0xf; 1109 iArray[outindex++] = element & 0xf; 1110 1111 bitnum += 32; 1112 } 1113 break; 1114 } 1115 1116 // Process final portion of scanline 1117 for (; i < w; i++) { 1118 int shift = shiftOffset - (bitnum & 7); 1119 iArray[outindex++] = 1120 bitMask & (data[index + (bitnum >> 3)] >> shift); 1121 bitnum += pixbits; 1122 } 1123 1124 index += scanlineStride; 1125 } 1126 1127 return iArray; 1128 } 1129 1130 /** 1131 * Sets all samples for a rectangle of pixels from an int array containing 1132 * one sample per array element. 1133 * An ArrayIndexOutOfBoundsException may be thrown if the coordinates are 1134 * not in bounds. 1135 * @param x The X coordinate of the upper left pixel location. 1136 * @param y The Y coordinate of the upper left pixel location. 1137 * @param w Width of the pixel rectangle. 1138 * @param h Height of the pixel rectangle. 1139 * @param iArray The input int pixel array. 1140 */ setPixels(int x, int y, int w, int h, int[] iArray)1141 public void setPixels(int x, int y, int w, int h, int[] iArray) { 1142 if ((x < this.minX) || (y < this.minY) || 1143 (x + w > this.maxX) || (y + h > this.maxY)) { 1144 throw new ArrayIndexOutOfBoundsException 1145 ("Coordinate out of bounds!"); 1146 } 1147 int pixbits = pixelBitStride; 1148 int scanbit = dataBitOffset + (x - minX) * pixbits; 1149 int index = (y - minY) * scanlineStride; 1150 int outindex = 0; 1151 byte[] data = this.data; 1152 for (int j = 0; j < h; j++) { 1153 int bitnum = scanbit; 1154 int element; 1155 1156 // Process initial portion of scanline 1157 int i = 0; 1158 while ((i < w) && ((bitnum & 7) != 0)) { 1159 int shift = shiftOffset - (bitnum & 7); 1160 element = data[index + (bitnum >> 3)]; 1161 element &= ~(bitMask << shift); 1162 element |= (iArray[outindex++] & bitMask) << shift; 1163 data[index + (bitnum >> 3)] = (byte)element; 1164 1165 bitnum += pixbits; 1166 i++; 1167 } 1168 1169 // Process central portion of scanline 8 pixels at a time 1170 int inIndex = index + (bitnum >> 3); 1171 switch (pixbits) { 1172 case 1: 1173 for (; i < w - 7; i += 8) { 1174 element = (iArray[outindex++] & 1) << 7; 1175 element |= (iArray[outindex++] & 1) << 6; 1176 element |= (iArray[outindex++] & 1) << 5; 1177 element |= (iArray[outindex++] & 1) << 4; 1178 element |= (iArray[outindex++] & 1) << 3; 1179 element |= (iArray[outindex++] & 1) << 2; 1180 element |= (iArray[outindex++] & 1) << 1; 1181 element |= (iArray[outindex++] & 1); 1182 data[inIndex++] = (byte)element; 1183 1184 bitnum += 8; 1185 } 1186 break; 1187 1188 case 2: 1189 for (; i < w - 7; i += 8) { 1190 element = (iArray[outindex++] & 3) << 6; 1191 element |= (iArray[outindex++] & 3) << 4; 1192 element |= (iArray[outindex++] & 3) << 2; 1193 element |= (iArray[outindex++] & 3); 1194 data[inIndex++] = (byte)element; 1195 1196 element = (iArray[outindex++] & 3) << 6; 1197 element |= (iArray[outindex++] & 3) << 4; 1198 element |= (iArray[outindex++] & 3) << 2; 1199 element |= (iArray[outindex++] & 3); 1200 data[inIndex++] = (byte)element; 1201 1202 bitnum += 16; 1203 } 1204 break; 1205 1206 case 4: 1207 for (; i < w - 7; i += 8) { 1208 element = (iArray[outindex++] & 0xf) << 4; 1209 element |= (iArray[outindex++] & 0xf); 1210 data[inIndex++] = (byte)element; 1211 1212 element = (iArray[outindex++] & 0xf) << 4; 1213 element |= (iArray[outindex++] & 0xf); 1214 data[inIndex++] = (byte)element; 1215 1216 element = (iArray[outindex++] & 0xf) << 4; 1217 element |= (iArray[outindex++] & 0xf); 1218 data[inIndex++] = (byte)element; 1219 1220 element = (iArray[outindex++] & 0xf) << 4; 1221 element |= (iArray[outindex++] & 0xf); 1222 data[inIndex++] = (byte)element; 1223 1224 bitnum += 32; 1225 } 1226 break; 1227 } 1228 1229 // Process final portion of scanline 1230 for (; i < w; i++) { 1231 int shift = shiftOffset - (bitnum & 7); 1232 1233 element = data[index + (bitnum >> 3)]; 1234 element &= ~(bitMask << shift); 1235 element |= (iArray[outindex++] & bitMask) << shift; 1236 data[index + (bitnum >> 3)] = (byte)element; 1237 1238 bitnum += pixbits; 1239 } 1240 1241 index += scanlineStride; 1242 } 1243 1244 markDirty(); 1245 } 1246 1247 /** 1248 * Creates a subraster given a region of the raster. The x and y 1249 * coordinates specify the horizontal and vertical offsets 1250 * from the upper-left corner of this raster to the upper-left corner 1251 * of the subraster. Note that the subraster will reference the same 1252 * DataBuffer as the parent raster, but using different offsets. The 1253 * bandList is ignored. 1254 * @param x X offset. 1255 * @param y Y offset. 1256 * @param width Width (in pixels) of the subraster. 1257 * @param height Height (in pixels) of the subraster. 1258 * @param x0 Translated X origin of the subraster. 1259 * @param y0 Translated Y origin of the subraster. 1260 * @param bandList Array of band indices. 1261 * @exception RasterFormatException 1262 * if the specified bounding box is outside of the parent raster. 1263 */ createChild(int x, int y, int width, int height, int x0, int y0, int[] bandList)1264 public Raster createChild(int x, int y, 1265 int width, int height, 1266 int x0, int y0, int[] bandList) { 1267 WritableRaster newRaster = createWritableChild(x, y, 1268 width, height, 1269 x0, y0, 1270 bandList); 1271 return (Raster) newRaster; 1272 } 1273 1274 /** 1275 * Creates a Writable subRaster given a region of the Raster. The x and y 1276 * coordinates specify the horizontal and vertical offsets 1277 * from the upper-left corner of this Raster to the upper-left corner 1278 * of the subRaster. The bandList is ignored. 1279 * A translation to the subRaster may also be specified. 1280 * Note that the subRaster will reference the same 1281 * DataBuffer as the parent Raster, but using different offsets. 1282 * @param x X offset. 1283 * @param y Y offset. 1284 * @param width Width (in pixels) of the subraster. 1285 * @param height Height (in pixels) of the subraster. 1286 * @param x0 Translated X origin of the subraster. 1287 * @param y0 Translated Y origin of the subraster. 1288 * @param bandList Array of band indices. 1289 * @exception RasterFormatException 1290 * if the specified bounding box is outside of the parent Raster. 1291 */ createWritableChild(int x, int y, int width, int height, int x0, int y0, int[] bandList)1292 public WritableRaster createWritableChild(int x, int y, 1293 int width, int height, 1294 int x0, int y0, 1295 int[] bandList) { 1296 if (x < this.minX) { 1297 throw new RasterFormatException("x lies outside the raster"); 1298 } 1299 if (y < this.minY) { 1300 throw new RasterFormatException("y lies outside the raster"); 1301 } 1302 if ((x+width < x) || (x+width > this.minX + this.width)) { 1303 throw new RasterFormatException("(x + width) is outside of Raster"); 1304 } 1305 if ((y+height < y) || (y+height > this.minY + this.height)) { 1306 throw new RasterFormatException("(y + height) is outside of Raster"); 1307 } 1308 1309 SampleModel sm; 1310 1311 if (bandList != null) { 1312 sm = sampleModel.createSubsetSampleModel(bandList); 1313 } 1314 else { 1315 sm = sampleModel; 1316 } 1317 1318 int deltaX = x0 - x; 1319 int deltaY = y0 - y; 1320 1321 return new BytePackedRaster(sm, 1322 (DataBufferByte) dataBuffer, 1323 new Rectangle(x0, y0, width, height), 1324 new Point(sampleModelTranslateX+deltaX, 1325 sampleModelTranslateY+deltaY), 1326 this); 1327 } 1328 1329 /** 1330 * Creates a raster with the same layout but using a different 1331 * width and height, and with new zeroed data arrays. 1332 */ createCompatibleWritableRaster(int w, int h)1333 public WritableRaster createCompatibleWritableRaster(int w, int h) { 1334 if (w <= 0 || h <=0) { 1335 throw new RasterFormatException("negative "+ 1336 ((w <= 0) ? "width" : "height")); 1337 } 1338 1339 SampleModel sm = sampleModel.createCompatibleSampleModel(w,h); 1340 1341 return new BytePackedRaster(sm, new Point(0,0)); 1342 } 1343 1344 /** 1345 * Creates a raster with the same layout and the same 1346 * width and height, and with new zeroed data arrays. 1347 */ createCompatibleWritableRaster()1348 public WritableRaster createCompatibleWritableRaster () { 1349 return createCompatibleWritableRaster(width,height); 1350 } 1351 1352 /** 1353 * Verify that the layout parameters are consistent with 1354 * the data. If strictCheck 1355 * is false, this method will check for ArrayIndexOutOfBounds conditions. 1356 * If strictCheck is true, this method will check for additional error 1357 * conditions such as line wraparound (width of a line greater than 1358 * the scanline stride). 1359 * @return String Error string, if the layout is incompatible with 1360 * the data. Otherwise returns null. 1361 */ verify(boolean strictCheck)1362 private void verify (boolean strictCheck) { 1363 // Make sure data for Raster is in a legal range 1364 if (dataBitOffset < 0) { 1365 throw new RasterFormatException("Data offsets must be >= 0"); 1366 } 1367 1368 /* Need to re-verify the dimensions since a sample model may be 1369 * specified to the constructor 1370 */ 1371 if (width <= 0 || height <= 0 || 1372 height > (Integer.MAX_VALUE / width)) 1373 { 1374 throw new RasterFormatException("Invalid raster dimension"); 1375 } 1376 1377 1378 /* 1379 * pixelBitstride was verified in constructor, so just make 1380 * sure that it is safe to multiply it by width. 1381 */ 1382 if ((width - 1) > Integer.MAX_VALUE / pixelBitStride) { 1383 throw new RasterFormatException("Invalid raster dimension"); 1384 } 1385 1386 if ((long)minX - sampleModelTranslateX < 0 || 1387 (long)minY - sampleModelTranslateY < 0) { 1388 1389 throw new RasterFormatException("Incorrect origin/translate: (" + 1390 minX + ", " + minY + ") / (" + 1391 sampleModelTranslateX + ", " + sampleModelTranslateY + ")"); 1392 } 1393 1394 if (scanlineStride < 0 || 1395 scanlineStride > (Integer.MAX_VALUE / height)) 1396 { 1397 throw new RasterFormatException("Invalid scanline stride"); 1398 } 1399 1400 if (height > 1 || minY - sampleModelTranslateY > 0) { 1401 // buffer should contain at least one scanline 1402 if (scanlineStride > data.length) { 1403 throw new RasterFormatException("Incorrect scanline stride: " 1404 + scanlineStride); 1405 } 1406 } 1407 1408 long lastbit = (long) dataBitOffset 1409 + (long) (height - 1) * (long) scanlineStride * 8 1410 + (long) (width - 1) * (long) pixelBitStride 1411 + (long) pixelBitStride - 1; 1412 if (lastbit < 0 || lastbit / 8 >= data.length) { 1413 throw new RasterFormatException("raster dimensions overflow " + 1414 "array bounds"); 1415 } 1416 if (strictCheck) { 1417 if (height > 1) { 1418 lastbit = width * pixelBitStride - 1; 1419 if (lastbit / 8 >= scanlineStride) { 1420 throw new RasterFormatException("data for adjacent" + 1421 " scanlines overlaps"); 1422 } 1423 } 1424 } 1425 } 1426 toString()1427 public String toString() { 1428 return new String ("BytePackedRaster: width = "+width+" height = "+height 1429 +" #channels "+numBands 1430 +" xOff = "+sampleModelTranslateX 1431 +" yOff = "+sampleModelTranslateY); 1432 } 1433 } 1434