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