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