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