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