0001: /*
0002: * Copyright 1997-2007 Sun Microsystems, Inc. All Rights Reserved.
0003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0004: *
0005: * This code is free software; you can redistribute it and/or modify it
0006: * under the terms of the GNU General Public License version 2 only, as
0007: * published by the Free Software Foundation. Sun designates this
0008: * particular file as subject to the "Classpath" exception as provided
0009: * by Sun in the LICENSE file that accompanied this code.
0010: *
0011: * This code is distributed in the hope that it will be useful, but WITHOUT
0012: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0013: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0014: * version 2 for more details (a copy is included in the LICENSE file that
0015: * accompanied this code).
0016: *
0017: * You should have received a copy of the GNU General Public License version
0018: * 2 along with this work; if not, write to the Free Software Foundation,
0019: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0020: *
0021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
0022: * CA 95054 USA or visit www.sun.com if you need additional information or
0023: * have any questions.
0024: */
0025:
0026: package sun.awt.image;
0027:
0028: import java.awt.image.Raster;
0029: import java.awt.image.WritableRaster;
0030: import java.awt.image.RasterFormatException;
0031: import java.awt.image.SampleModel;
0032: import java.awt.image.MultiPixelPackedSampleModel;
0033: import java.awt.image.DataBuffer;
0034: import java.awt.image.DataBufferByte;
0035: import java.awt.Rectangle;
0036: import java.awt.Point;
0037:
0038: /**
0039: * This class is useful for describing 1, 2, or 4 bit image data
0040: * elements. This raster has one band whose pixels are packed
0041: * together into individual bytes in a single byte array. This type
0042: * of raster can be used with an IndexColorModel. This raster uses a
0043: * MultiPixelPackedSampleModel.
0044: *
0045: * @version 10 Feb 1997
0046: */
0047: public class BytePackedRaster extends SunWritableRaster {
0048:
0049: /** The data bit offset for each pixel. */
0050: int dataBitOffset;
0051:
0052: /** Scanline stride of the image data contained in this Raster. */
0053: int scanlineStride;
0054:
0055: /**
0056: * The bit stride of a pixel, equal to the total number of bits
0057: * required to store a pixel.
0058: */
0059: int pixelBitStride;
0060:
0061: /** The bit mask for extracting the pixel. */
0062: int bitMask;
0063:
0064: /** The image data array. */
0065: byte[] data;
0066:
0067: /** 8 minus the pixel bit stride. */
0068: int shiftOffset;
0069:
0070: int type;
0071:
0072: /** A cached copy of minX + width for use in bounds checks. */
0073: private int maxX;
0074:
0075: /** A cached copy of minY + height for use in bounds checks. */
0076: private int maxY;
0077:
0078: static private native void initIDs();
0079:
0080: static {
0081: /* ensure that the necessary native libraries are loaded */
0082: NativeLibLoader.loadLibraries();
0083: initIDs();
0084: }
0085:
0086: /**
0087: * Constructs a BytePackedRaster with the given SampleModel.
0088: * The Raster's upper left corner is origin and it is the same
0089: * size as the SampleModel. A DataBuffer large enough to describe the
0090: * Raster is automatically created. SampleModel must be of type
0091: * MultiPixelPackedSampleModel.
0092: * @param sampleModel The SampleModel that specifies the layout.
0093: * @param origin The Point that specified the origin.
0094: */
0095: public BytePackedRaster(SampleModel sampleModel, Point origin) {
0096: this (sampleModel, sampleModel.createDataBuffer(),
0097: new Rectangle(origin.x, origin.y, sampleModel
0098: .getWidth(), sampleModel.getHeight()), origin,
0099: null);
0100: }
0101:
0102: /**
0103: * Constructs a BytePackedRaster with the given SampleModel
0104: * and DataBuffer. The Raster's upper left corner is origin and
0105: * it is the same size as the SampleModel. The DataBuffer is not
0106: * initialized and must be a DataBufferByte compatible with SampleModel.
0107: * SampleModel must be of type MultiPixelPackedSampleModel.
0108: * @param sampleModel The SampleModel that specifies the layout.
0109: * @param dataBuffer The DataBufferShort that contains the image data.
0110: * @param origin The Point that specifies the origin.
0111: */
0112: public BytePackedRaster(SampleModel sampleModel,
0113: DataBuffer dataBuffer, Point origin) {
0114: this (sampleModel, dataBuffer, new Rectangle(origin.x, origin.y,
0115: sampleModel.getWidth(), sampleModel.getHeight()),
0116: origin, null);
0117: }
0118:
0119: /**
0120: * Constructs a BytePackedRaster with the given SampleModel,
0121: * DataBuffer, and parent. DataBuffer must be a DataBufferByte and
0122: * SampleModel must be of type MultiPixelPackedSampleModel.
0123: * When translated into the base Raster's
0124: * coordinate system, aRegion must be contained by the base Raster.
0125: * Origin is the coordinate in the new Raster's coordinate system of
0126: * the origin of the base Raster. (The base Raster is the Raster's
0127: * ancestor which has no parent.)
0128: *
0129: * Note that this constructor should generally be called by other
0130: * constructors or create methods, it should not be used directly.
0131: * @param sampleModel The SampleModel that specifies the layout.
0132: * @param dataBuffer The DataBufferShort that contains the image data.
0133: * @param aRegion The Rectangle that specifies the image area.
0134: * @param origin The Point that specifies the origin.
0135: * @param parent The parent (if any) of this raster.
0136: *
0137: * @exception RasterFormatException if the parameters do not conform
0138: * to requirements of this Raster type.
0139: */
0140: public BytePackedRaster(SampleModel sampleModel,
0141: DataBuffer dataBuffer, Rectangle aRegion, Point origin,
0142: BytePackedRaster parent) {
0143: super (sampleModel, dataBuffer, aRegion, origin, parent);
0144: this .maxX = minX + width;
0145: this .maxY = minY + height;
0146:
0147: if (!(dataBuffer instanceof DataBufferByte)) {
0148: throw new RasterFormatException(
0149: "BytePackedRasters must have" + "byte DataBuffers");
0150: }
0151: DataBufferByte dbb = (DataBufferByte) dataBuffer;
0152: this .data = stealData(dbb, 0);
0153: if (dbb.getNumBanks() != 1) {
0154: throw new RasterFormatException(
0155: "DataBuffer for BytePackedRasters"
0156: + " must only have 1 bank.");
0157: }
0158: int dbOffset = dbb.getOffset();
0159:
0160: if (sampleModel instanceof MultiPixelPackedSampleModel) {
0161: MultiPixelPackedSampleModel mppsm = (MultiPixelPackedSampleModel) sampleModel;
0162: this .type = IntegerComponentRaster.TYPE_BYTE_BINARY_SAMPLES;
0163: pixelBitStride = mppsm.getPixelBitStride();
0164: if (pixelBitStride != 1 && pixelBitStride != 2
0165: && pixelBitStride != 4) {
0166: throw new RasterFormatException(
0167: "BytePackedRasters must have a bit depth of 1, 2, or 4");
0168: }
0169: scanlineStride = mppsm.getScanlineStride();
0170: dataBitOffset = mppsm.getDataBitOffset() + dbOffset * 8;
0171: int xOffset = aRegion.x - origin.x;
0172: int yOffset = aRegion.y - origin.y;
0173: dataBitOffset += xOffset * pixelBitStride + yOffset
0174: * scanlineStride * 8;
0175: bitMask = (1 << pixelBitStride) - 1;
0176: shiftOffset = 8 - pixelBitStride;
0177: } else {
0178: throw new RasterFormatException(
0179: "BytePackedRasters must have"
0180: + "MultiPixelPackedSampleModel");
0181: }
0182: verify(false);
0183: }
0184:
0185: /**
0186: * Returns the data bit offset for the Raster. The data
0187: * bit offset is the bit index into the data array element
0188: * corresponding to the first sample of the first scanline.
0189: */
0190: public int getDataBitOffset() {
0191: return dataBitOffset;
0192: }
0193:
0194: /**
0195: * Returns the scanline stride -- the number of data array elements between
0196: * a given sample and the sample in the same column
0197: * of the next row.
0198: */
0199: public int getScanlineStride() {
0200: return scanlineStride;
0201: }
0202:
0203: /**
0204: * Returns pixel bit stride -- the number of bits between two
0205: * samples on the same scanline.
0206: */
0207: public int getPixelBitStride() {
0208: return pixelBitStride;
0209: }
0210:
0211: /**
0212: * Returns a reference to the entire data array.
0213: */
0214: public byte[] getDataStorage() {
0215: return data;
0216: }
0217:
0218: /**
0219: * Returns the data element at the specified
0220: * location.
0221: * An ArrayIndexOutOfBounds exception will be thrown at runtime
0222: * if the pixel coordinate is out of bounds.
0223: * A ClassCastException will be thrown if the input object is non null
0224: * and references anything other than an array of transferType.
0225: * @param x The X coordinate of the pixel location.
0226: * @param y The Y coordinate of the pixel location.
0227: * @param outData An object reference to an array of type defined by
0228: * getTransferType() and length getNumDataElements().
0229: * If null an array of appropriate type and size will be
0230: * allocated.
0231: * @return An object reference to an array of type defined by
0232: * getTransferType() with the request pixel data.
0233: */
0234: public Object getDataElements(int x, int y, Object obj) {
0235: if ((x < this .minX) || (y < this .minY) || (x >= this .maxX)
0236: || (y >= this .maxY)) {
0237: throw new ArrayIndexOutOfBoundsException(
0238: "Coordinate out of bounds!");
0239: }
0240: byte outData[];
0241: if (obj == null) {
0242: outData = new byte[numDataElements];
0243: } else {
0244: outData = (byte[]) obj;
0245: }
0246: int bitnum = dataBitOffset + (x - minX) * pixelBitStride;
0247: // Fix 4184283
0248: int element = data[(y - minY) * scanlineStride + (bitnum >> 3)] & 0xff;
0249: int shift = shiftOffset - (bitnum & 7);
0250: outData[0] = (byte) ((element >> shift) & bitMask);
0251: return outData;
0252: }
0253:
0254: /**
0255: * Returns the pixel data for the specified rectangle of pixels in a
0256: * primitive array of type TransferType.
0257: * For image data supported by the Java 2D API, this
0258: * will be one of DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT, or
0259: * DataBuffer.TYPE_INT. Data may be returned in a packed format,
0260: * thus increasing efficiency for data transfers.
0261: *
0262: * An ArrayIndexOutOfBoundsException may be thrown
0263: * if the coordinates are not in bounds.
0264: * A ClassCastException will be thrown if the input object is non null
0265: * and references anything other than an array of TransferType.
0266: * @see java.awt.image.SampleModel#getDataElements(int, int, int, int, Object, DataBuffer)
0267: * @param x The X coordinate of the upper left pixel location.
0268: * @param y The Y coordinate of the upper left pixel location.
0269: * @param w Width of the pixel rectangle.
0270: * @param h Height of the pixel rectangle.
0271: * @param outData An object reference to an array of type defined by
0272: * getTransferType() and length w*h*getNumDataElements().
0273: * If null, an array of appropriate type and size will be
0274: * allocated.
0275: * @return An object reference to an array of type defined by
0276: * getTransferType() with the requested pixel data.
0277: */
0278: public Object getDataElements(int x, int y, int w, int h,
0279: Object outData) {
0280: return getByteData(x, y, w, h, (byte[]) outData);
0281: }
0282:
0283: /**
0284: * Returns an array of data elements from the specified rectangular
0285: * region.
0286: *
0287: * An ArrayIndexOutOfBounds exception will be thrown at runtime
0288: * if the pixel coordinates are out of bounds.
0289: * A ClassCastException will be thrown if the input object is non null
0290: * and references anything other than an array of transferType.
0291: * <pre>
0292: * byte[] bandData = (byte[])raster.getPixelData(x, y, w, h, null);
0293: * int pixel;
0294: * // To find a data element at location (x2, y2)
0295: * pixel = bandData[((y2-y)*w + (x2-x))];
0296: * </pre>
0297: * @param x The X coordinate of the upper left pixel location.
0298: * @param y The Y coordinate of the upper left pixel location.
0299: * @param width Width of the pixel rectangle.
0300: * @param height Height of the pixel rectangle.
0301: * @param outData An object reference to an array of type defined by
0302: * getTransferType() and length w*h*getNumDataElements().
0303: * If null an array of appropriate type and size will be
0304: * allocated.
0305: * @return An object reference to an array of type defined by
0306: * getTransferType() with the request pixel data.
0307: */
0308: public Object getPixelData(int x, int y, int w, int h, Object obj) {
0309: if ((x < this .minX) || (y < this .minY) || (x + w > this .maxX)
0310: || (y + h > this .maxY)) {
0311: throw new ArrayIndexOutOfBoundsException(
0312: "Coordinate out of bounds!");
0313: }
0314: byte outData[];
0315: if (obj == null) {
0316: outData = new byte[numDataElements * w * h];
0317: } else {
0318: outData = (byte[]) obj;
0319: }
0320: int pixbits = pixelBitStride;
0321: int scanbit = dataBitOffset + (x - minX) * pixbits;
0322: int index = (y - minY) * scanlineStride;
0323: int outindex = 0;
0324: byte data[] = this .data;
0325:
0326: for (int j = 0; j < h; j++) {
0327: int bitnum = scanbit;
0328: for (int i = 0; i < w; i++) {
0329: int shift = shiftOffset - (bitnum & 7);
0330: outData[outindex++] = (byte) (bitMask & (data[index
0331: + (bitnum >> 3)] >> shift));
0332: bitnum += pixbits;
0333: }
0334: index += scanlineStride;
0335: }
0336: return outData;
0337: }
0338:
0339: /**
0340: * Returns a byte array containing the specified data elements
0341: * from the data array. The band index will be ignored.
0342: * An ArrayIndexOutOfBounds exception will be thrown at runtime
0343: * if the pixel coordinates are out of bounds.
0344: * <pre>
0345: * byte[] byteData = getByteData(x, y, band, w, h, null);
0346: * // To find a data element at location (x2, y2)
0347: * byte element = byteData[(y2-y)*w + (x2-x)];
0348: * </pre>
0349: * @param x The X coordinate of the upper left pixel location.
0350: * @param y The Y coordinate of the upper left pixel location.
0351: * @param width Width of the pixel rectangle.
0352: * @param height Height of the pixel rectangle.
0353: * @param band The band to return, is ignored.
0354: * @param outData If non-null, data elements
0355: * at the specified locations are returned in this array.
0356: * @return Byte array with data elements.
0357: */
0358: public byte[] getByteData(int x, int y, int w, int h, int band,
0359: byte[] outData) {
0360: return getByteData(x, y, w, h, outData);
0361: }
0362:
0363: /**
0364: * Returns a byte array containing the specified data elements
0365: * from the data array.
0366: * An ArrayIndexOutOfBounds exception will be thrown at runtime
0367: * if the pixel coordinates are out of bounds.
0368: * <pre>
0369: * byte[] byteData = raster.getByteData(x, y, w, h, null);
0370: * byte pixel;
0371: * // To find a data element at location (x2, y2)
0372: * pixel = byteData[((y2-y)*w + (x2-x))];
0373: * </pre>
0374: * @param x The X coordinate of the upper left pixel location.
0375: * @param y The Y coordinate of the upper left pixel location.
0376: * @param width Width of the pixel rectangle.
0377: * @param height Height of the pixel rectangle.
0378: * @param outData If non-null, data elements
0379: * at the specified locations are returned in this array.
0380: * @return Byte array with data elements.
0381: */
0382: public byte[] getByteData(int x, int y, int w, int h, byte[] outData) {
0383: if ((x < this .minX) || (y < this .minY) || (x + w > this .maxX)
0384: || (y + h > this .maxY)) {
0385: throw new ArrayIndexOutOfBoundsException(
0386: "Coordinate out of bounds!");
0387: }
0388: if (outData == null) {
0389: outData = new byte[w * h];
0390: }
0391: int pixbits = pixelBitStride;
0392: int scanbit = dataBitOffset + (x - minX) * pixbits;
0393: int index = (y - minY) * scanlineStride;
0394: int outindex = 0;
0395: byte data[] = this .data;
0396:
0397: for (int j = 0; j < h; j++) {
0398: int bitnum = scanbit;
0399: int element;
0400:
0401: // Process initial portion of scanline
0402: int i = 0;
0403: while ((i < w) && ((bitnum & 7) != 0)) {
0404: int shift = shiftOffset - (bitnum & 7);
0405: outData[outindex++] = (byte) (bitMask & (data[index
0406: + (bitnum >> 3)] >> shift));
0407: bitnum += pixbits;
0408: i++;
0409: }
0410:
0411: // Process central portion of scanline 8 pixels at a time
0412: int inIndex = index + (bitnum >> 3);
0413: switch (pixbits) {
0414: case 1:
0415: for (; i < w - 7; i += 8) {
0416: element = data[inIndex++];
0417: outData[outindex++] = (byte) ((element >> 7) & 1);
0418: outData[outindex++] = (byte) ((element >> 6) & 1);
0419: outData[outindex++] = (byte) ((element >> 5) & 1);
0420: outData[outindex++] = (byte) ((element >> 4) & 1);
0421: outData[outindex++] = (byte) ((element >> 3) & 1);
0422: outData[outindex++] = (byte) ((element >> 2) & 1);
0423: outData[outindex++] = (byte) ((element >> 1) & 1);
0424: outData[outindex++] = (byte) (element & 1);
0425: bitnum += 8;
0426: }
0427: break;
0428:
0429: case 2:
0430: for (; i < w - 7; i += 8) {
0431: element = data[inIndex++];
0432: outData[outindex++] = (byte) ((element >> 6) & 3);
0433: outData[outindex++] = (byte) ((element >> 4) & 3);
0434: outData[outindex++] = (byte) ((element >> 2) & 3);
0435: outData[outindex++] = (byte) (element & 3);
0436:
0437: element = data[inIndex++];
0438: outData[outindex++] = (byte) ((element >> 6) & 3);
0439: outData[outindex++] = (byte) ((element >> 4) & 3);
0440: outData[outindex++] = (byte) ((element >> 2) & 3);
0441: outData[outindex++] = (byte) (element & 3);
0442:
0443: bitnum += 16;
0444: }
0445: break;
0446:
0447: case 4:
0448: for (; i < w - 7; i += 8) {
0449: element = data[inIndex++];
0450: outData[outindex++] = (byte) ((element >> 4) & 0xf);
0451: outData[outindex++] = (byte) (element & 0xf);
0452:
0453: element = data[inIndex++];
0454: outData[outindex++] = (byte) ((element >> 4) & 0xf);
0455: outData[outindex++] = (byte) (element & 0xf);
0456:
0457: element = data[inIndex++];
0458: outData[outindex++] = (byte) ((element >> 4) & 0xf);
0459: outData[outindex++] = (byte) (element & 0xf);
0460:
0461: element = data[inIndex++];
0462: outData[outindex++] = (byte) ((element >> 4) & 0xf);
0463: outData[outindex++] = (byte) (element & 0xf);
0464:
0465: bitnum += 32;
0466: }
0467: break;
0468: }
0469:
0470: // Process final portion of scanline
0471: for (; i < w; i++) {
0472: int shift = shiftOffset - (bitnum & 7);
0473: outData[outindex++] = (byte) (bitMask & (data[index
0474: + (bitnum >> 3)] >> shift));
0475: bitnum += pixbits;
0476: }
0477:
0478: index += scanlineStride;
0479: }
0480:
0481: return outData;
0482: }
0483:
0484: /**
0485: * Stores the data elements at the specified location.
0486: * An ArrayIndexOutOfBounds exception will be thrown at runtime
0487: * if the pixel coordinate is out of bounds.
0488: * A ClassCastException will be thrown if the input object is non null
0489: * and references anything other than an array of transferType.
0490: * @param x The X coordinate of the pixel location.
0491: * @param y The Y coordinate of the pixel location.
0492: * @param inData An object reference to an array of type defined by
0493: * getTransferType() and length getNumDataElements()
0494: * containing the pixel data to place at x,y.
0495: */
0496: public void setDataElements(int x, int y, Object obj) {
0497: if ((x < this .minX) || (y < this .minY) || (x >= this .maxX)
0498: || (y >= this .maxY)) {
0499: throw new ArrayIndexOutOfBoundsException(
0500: "Coordinate out of bounds!");
0501: }
0502: byte inData[] = (byte[]) obj;
0503: int bitnum = dataBitOffset + (x - minX) * pixelBitStride;
0504: int index = (y - minY) * scanlineStride + (bitnum >> 3);
0505: int shift = shiftOffset - (bitnum & 7);
0506:
0507: byte element = data[index];
0508: element &= ~(bitMask << shift);
0509: element |= (inData[0] & bitMask) << shift;
0510: data[index] = element;
0511:
0512: markDirty();
0513: }
0514:
0515: /**
0516: * Stores the Raster data at the specified location.
0517: * An ArrayIndexOutOfBounds exception will be thrown at runtime
0518: * if the pixel coordinates are out of bounds.
0519: * @param x The X coordinate of the pixel location.
0520: * @param y The Y coordinate of the pixel location.
0521: * @param inRaster Raster of data to place at x,y location.
0522: */
0523: public void setDataElements(int x, int y, Raster inRaster) {
0524: // Check if we can use fast code
0525: if (!(inRaster instanceof BytePackedRaster)
0526: || ((BytePackedRaster) inRaster).pixelBitStride != pixelBitStride) {
0527: super .setDataElements(x, y, inRaster);
0528: return;
0529: }
0530:
0531: int srcOffX = inRaster.getMinX();
0532: int srcOffY = inRaster.getMinY();
0533: int dstOffX = srcOffX + x;
0534: int dstOffY = srcOffY + y;
0535: int width = inRaster.getWidth();
0536: int height = inRaster.getHeight();
0537: if ((dstOffX < this .minX) || (dstOffY < this .minY)
0538: || (dstOffX + width > this .maxX)
0539: || (dstOffY + height > this .maxY)) {
0540: throw new ArrayIndexOutOfBoundsException(
0541: "Coordinate out of bounds!");
0542: }
0543: setDataElements(dstOffX, dstOffY, srcOffX, srcOffY, width,
0544: height, (BytePackedRaster) inRaster);
0545: }
0546:
0547: /**
0548: * Stores the Raster data at the specified location.
0549: * @param dstX The absolute X coordinate of the destination pixel
0550: * that will receive a copy of the upper-left pixel of the
0551: * inRaster
0552: * @param dstY The absolute Y coordinate of the destination pixel
0553: * that will receive a copy of the upper-left pixel of the
0554: * inRaster
0555: * @param srcX The absolute X coordinate of the upper-left source
0556: * pixel that will be copied into this Raster
0557: * @param srcY The absolute Y coordinate of the upper-left source
0558: * pixel that will be copied into this Raster
0559: * @param width The number of pixels to store horizontally
0560: * @param height The number of pixels to store vertically
0561: * @param inRaster BytePackedRaster of data to place at x,y location.
0562: */
0563: private void setDataElements(int dstX, int dstY, int srcX,
0564: int srcY, int width, int height, BytePackedRaster inRaster) {
0565: // Assume bounds checking has been performed previously
0566: if (width <= 0 || height <= 0) {
0567: return;
0568: }
0569:
0570: byte[] inData = inRaster.data;
0571: byte[] outData = this .data;
0572:
0573: int inscan = inRaster.scanlineStride;
0574: int outscan = this .scanlineStride;
0575: int inbit = inRaster.dataBitOffset + 8 * (srcY - inRaster.minY)
0576: * inscan + (srcX - inRaster.minX)
0577: * inRaster.pixelBitStride;
0578: int outbit = (this .dataBitOffset + 8 * (dstY - minY) * outscan + (dstX - minX)
0579: * this .pixelBitStride);
0580: int copybits = width * pixelBitStride;
0581:
0582: // Check whether the same bit alignment is present in both
0583: // Rasters; if so, we can copy whole bytes using
0584: // System.arraycopy. If not, we must do a "funnel shift"
0585: // where adjacent bytes contribute to each destination byte.
0586: if ((inbit & 7) == (outbit & 7)) {
0587: // copy is bit aligned
0588: int bitpos = outbit & 7;
0589: if (bitpos != 0) {
0590: int bits = 8 - bitpos;
0591: // Copy partial bytes on left
0592: int inbyte = inbit >> 3;
0593: int outbyte = outbit >> 3;
0594: int mask = 0xff >> bitpos;
0595: if (copybits < bits) {
0596: // Fix bug 4399076: previously had '8 - copybits' instead
0597: // of 'bits - copybits'.
0598: //
0599: // Prior to the this expression, 'mask' has its rightmost
0600: // 'bits' bits set to '1'. We want it to have a total
0601: // of 'copybits' bits set, therefore we want to introduce
0602: // 'bits - copybits' zeroes on the right.
0603: mask &= 0xff << (bits - copybits);
0604: bits = copybits;
0605: }
0606: for (int j = 0; j < height; j++) {
0607: int element = outData[outbyte];
0608: element &= ~mask;
0609: element |= (inData[inbyte] & mask);
0610: outData[outbyte] = (byte) element;
0611: inbyte += inscan;
0612: outbyte += outscan;
0613: }
0614: inbit += bits;
0615: outbit += bits;
0616: copybits -= bits;
0617: }
0618: if (copybits >= 8) {
0619: // Copy whole bytes
0620: int inbyte = inbit >> 3;
0621: int outbyte = outbit >> 3;
0622: int copybytes = copybits >> 3;
0623: if (copybytes == inscan && inscan == outscan) {
0624: System.arraycopy(inData, inbyte, outData, outbyte,
0625: inscan * height);
0626: } else {
0627: for (int j = 0; j < height; j++) {
0628: System.arraycopy(inData, inbyte, outData,
0629: outbyte, copybytes);
0630: inbyte += inscan;
0631: outbyte += outscan;
0632: }
0633: }
0634:
0635: int bits = copybytes * 8;
0636: inbit += bits;
0637: outbit += bits;
0638: copybits -= bits;
0639: }
0640: if (copybits > 0) {
0641: // Copy partial bytes on right
0642: int inbyte = inbit >> 3;
0643: int outbyte = outbit >> 3;
0644: int mask = (0xff00 >> copybits) & 0xff;
0645: for (int j = 0; j < height; j++) {
0646: int element = outData[outbyte];
0647: element &= ~mask;
0648: element |= (inData[inbyte] & mask);
0649: outData[outbyte] = (byte) element;
0650: inbyte += inscan;
0651: outbyte += outscan;
0652: }
0653: }
0654: } else {
0655: // Unaligned case, see RFE #4284166
0656: // Note that the code in that RFE is not correct
0657:
0658: // Insert bits into the first byte of the output
0659: // if either the starting bit position is not zero or
0660: // we are writing fewer than 8 bits in total
0661: int bitpos = outbit & 7;
0662: if (bitpos != 0 || copybits < 8) {
0663: int bits = 8 - bitpos;
0664: int inbyte = inbit >> 3;
0665: int outbyte = outbit >> 3;
0666:
0667: int lshift = inbit & 7;
0668: int rshift = 8 - lshift;
0669: int mask = 0xff >> bitpos;
0670: if (copybits < bits) {
0671: // Fix mask if we're only writing a partial byte
0672: mask &= 0xff << (bits - copybits);
0673: bits = copybits;
0674: }
0675: int lastByte = inData.length - 1;
0676: for (int j = 0; j < height; j++) {
0677: // Read two bytes from the source if possible
0678: // Don't worry about going over a scanline boundary
0679: // since any extra bits won't get used anyway
0680: byte inData0 = inData[inbyte];
0681: byte inData1 = (byte) 0;
0682: if (inbyte < lastByte) {
0683: inData1 = inData[inbyte + 1];
0684: }
0685:
0686: // Insert the new bits into the output
0687: int element = outData[outbyte];
0688: element &= ~mask;
0689: element |= (((inData0 << lshift) | ((inData1 & 0xff) >> rshift)) >> bitpos)
0690: & mask;
0691: outData[outbyte] = (byte) element;
0692: inbyte += inscan;
0693: outbyte += outscan;
0694: }
0695:
0696: inbit += bits;
0697: outbit += bits;
0698: copybits -= bits;
0699: }
0700:
0701: // Now we have outbit & 7 == 0 so we can write
0702: // complete bytes for a while
0703:
0704: // Make sure we have work to do in the central loop
0705: // to avoid reading past the end of the scanline
0706: if (copybits >= 8) {
0707: int inbyte = inbit >> 3;
0708: int outbyte = outbit >> 3;
0709: int copybytes = copybits >> 3;
0710: int lshift = inbit & 7;
0711: int rshift = 8 - lshift;
0712:
0713: for (int j = 0; j < height; j++) {
0714: int ibyte = inbyte + j * inscan;
0715: int obyte = outbyte + j * outscan;
0716:
0717: int inData0 = inData[ibyte];
0718: // Combine adjacent bytes while 8 or more bits left
0719: for (int i = 0; i < copybytes; i++) {
0720: int inData1 = inData[ibyte + 1];
0721: int val = (inData0 << lshift)
0722: | ((inData1 & 0xff) >> rshift);
0723: outData[obyte] = (byte) val;
0724: inData0 = inData1;
0725:
0726: ++ibyte;
0727: ++obyte;
0728: }
0729: }
0730:
0731: int bits = copybytes * 8;
0732: inbit += bits;
0733: outbit += bits;
0734: copybits -= bits;
0735: }
0736:
0737: // Finish last byte
0738: if (copybits > 0) {
0739: int inbyte = inbit >> 3;
0740: int outbyte = outbit >> 3;
0741: int mask = (0xff00 >> copybits) & 0xff;
0742: int lshift = inbit & 7;
0743: int rshift = 8 - lshift;
0744:
0745: int lastByte = inData.length - 1;
0746: for (int j = 0; j < height; j++) {
0747: byte inData0 = inData[inbyte];
0748: byte inData1 = (byte) 0;
0749: if (inbyte < lastByte) {
0750: inData1 = inData[inbyte + 1];
0751: }
0752:
0753: // Insert the new bits into the output
0754: int element = outData[outbyte];
0755: element &= ~mask;
0756: element |= ((inData0 << lshift) | ((inData1 & 0xff) >> rshift))
0757: & mask;
0758: outData[outbyte] = (byte) element;
0759:
0760: inbyte += inscan;
0761: outbyte += outscan;
0762: }
0763: }
0764: }
0765:
0766: markDirty();
0767: }
0768:
0769: /**
0770: * Copies pixels from Raster srcRaster to this WritableRaster.
0771: * For each (x, y) address in srcRaster, the corresponding pixel
0772: * is copied to address (x+dx, y+dy) in this WritableRaster,
0773: * unless (x+dx, y+dy) falls outside the bounds of this raster.
0774: * srcRaster must have the same number of bands as this WritableRaster.
0775: * The copy is a simple copy of source samples to the corresponding
0776: * destination samples. For details, see
0777: * {@link WritableRaster#setRect(Raster)}.
0778: *
0779: * @param dx The X translation factor from src space to dst space
0780: * of the copy.
0781: * @param dy The Y translation factor from src space to dst space
0782: * of the copy.
0783: * @param srcRaster The Raster from which to copy pixels.
0784: */
0785: public void setRect(int dx, int dy, Raster srcRaster) {
0786: // Check if we can use fast code
0787: if (!(srcRaster instanceof BytePackedRaster)
0788: || ((BytePackedRaster) srcRaster).pixelBitStride != pixelBitStride) {
0789: super .setRect(dx, dy, srcRaster);
0790: return;
0791: }
0792:
0793: int width = srcRaster.getWidth();
0794: int height = srcRaster.getHeight();
0795: int srcOffX = srcRaster.getMinX();
0796: int srcOffY = srcRaster.getMinY();
0797: int dstOffX = dx + srcOffX;
0798: int dstOffY = dy + srcOffY;
0799:
0800: // Clip to this raster
0801: if (dstOffX < this .minX) {
0802: int skipX = this .minX - dstOffX;
0803: width -= skipX;
0804: srcOffX += skipX;
0805: dstOffX = this .minX;
0806: }
0807: if (dstOffY < this .minY) {
0808: int skipY = this .minY - dstOffY;
0809: height -= skipY;
0810: srcOffY += skipY;
0811: dstOffY = this .minY;
0812: }
0813: if (dstOffX + width > this .maxX) {
0814: width = this .maxX - dstOffX;
0815: }
0816: if (dstOffY + height > this .maxY) {
0817: height = this .maxY - dstOffY;
0818: }
0819:
0820: setDataElements(dstOffX, dstOffY, srcOffX, srcOffY, width,
0821: height, (BytePackedRaster) srcRaster);
0822: }
0823:
0824: /**
0825: * Stores an array of data elements into the specified rectangular
0826: * region.
0827: * An ArrayIndexOutOfBounds exception will be thrown at runtime
0828: * if the pixel coordinates are out of bounds.
0829: * A ClassCastException will be thrown if the input object is non null
0830: * and references anything other than an array of transferType.
0831: * The data elements in the
0832: * data array are assumed to be packed. That is, a data element
0833: * at location (x2, y2) would be found at:
0834: * <pre>
0835: * inData[((y2-y)*w + (x2-x))]
0836: * </pre>
0837: * @param x The X coordinate of the upper left pixel location.
0838: * @param y The Y coordinate of the upper left pixel location.
0839: * @param w Width of the pixel rectangle.
0840: * @param h Height of the pixel rectangle.
0841: * @param inData An object reference to an array of type defined by
0842: * getTransferType() and length w*h*getNumDataElements()
0843: * containing the pixel data to place between x,y and
0844: * x+h, y+h.
0845: */
0846: public void setDataElements(int x, int y, int w, int h, Object obj) {
0847: putByteData(x, y, w, h, (byte[]) obj);
0848: }
0849:
0850: /**
0851: * Stores a byte array of data elements into the specified rectangular
0852: * region. The band index will be ignored.
0853: * An ArrayIndexOutOfBounds exception will be thrown at runtime
0854: * if the pixel coordinates are out of bounds.
0855: * The data elements in the
0856: * data array are assumed to be packed. That is, a data element
0857: * at location (x2, y2) would be found at:
0858: * <pre>
0859: * inData[((y2-y)*w + (x2-x))]
0860: * </pre>
0861: * @param x The X coordinate of the upper left pixel location.
0862: * @param y The Y coordinate of the upper left pixel location.
0863: * @param w Width of the pixel rectangle.
0864: * @param h Height of the pixel rectangle.
0865: * @param band The band to set, is ignored.
0866: * @param inData The data elements to be stored.
0867: */
0868: public void putByteData(int x, int y, int w, int h, int band,
0869: byte[] inData) {
0870: putByteData(x, y, w, h, inData);
0871: }
0872:
0873: /**
0874: * Stores a byte array of data elements into the specified rectangular
0875: * region.
0876: * An ArrayIndexOutOfBounds exception will be thrown at runtime
0877: * if the pixel coordinates are out of bounds.
0878: * The data elements in the
0879: * data array are assumed to be packed. That is, a data element
0880: * at location (x2, y2) would be found at:
0881: * <pre>
0882: * inData[((y2-y)*w + (x2-x))]
0883: * </pre>
0884: * @param x The X coordinate of the upper left pixel location.
0885: * @param y The Y coordinate of the upper left pixel location.
0886: * @param w Width of the pixel rectangle.
0887: * @param h Height of the pixel rectangle.
0888: * @param inData The data elements to be stored.
0889: */
0890: public void putByteData(int x, int y, int w, int h, byte[] inData) {
0891: if ((x < this .minX) || (y < this .minY) || (x + w > this .maxX)
0892: || (y + h > this .maxY)) {
0893: throw new ArrayIndexOutOfBoundsException(
0894: "Coordinate out of bounds!");
0895: }
0896: if (w == 0 || h == 0) {
0897: return;
0898: }
0899:
0900: int pixbits = pixelBitStride;
0901: int scanbit = dataBitOffset + (x - minX) * pixbits;
0902: int index = (y - minY) * scanlineStride;
0903: int outindex = 0;
0904: byte data[] = this .data;
0905: for (int j = 0; j < h; j++) {
0906: int bitnum = scanbit;
0907: int element;
0908:
0909: // Process initial portion of scanline
0910: int i = 0;
0911: while ((i < w) && ((bitnum & 7) != 0)) {
0912: int shift = shiftOffset - (bitnum & 7);
0913: element = data[index + (bitnum >> 3)];
0914: element &= ~(bitMask << shift);
0915: element |= (inData[outindex++] & bitMask) << shift;
0916: data[index + (bitnum >> 3)] = (byte) element;
0917:
0918: bitnum += pixbits;
0919: i++;
0920: }
0921:
0922: // Process central portion of scanline 8 pixels at a time
0923: int inIndex = index + (bitnum >> 3);
0924: switch (pixbits) {
0925: case 1:
0926: for (; i < w - 7; i += 8) {
0927: element = (inData[outindex++] & 1) << 7;
0928: element |= (inData[outindex++] & 1) << 6;
0929: element |= (inData[outindex++] & 1) << 5;
0930: element |= (inData[outindex++] & 1) << 4;
0931: element |= (inData[outindex++] & 1) << 3;
0932: element |= (inData[outindex++] & 1) << 2;
0933: element |= (inData[outindex++] & 1) << 1;
0934: element |= (inData[outindex++] & 1);
0935:
0936: data[inIndex++] = (byte) element;
0937:
0938: bitnum += 8;
0939: }
0940: break;
0941:
0942: case 2:
0943: for (; i < w - 7; i += 8) {
0944: element = (inData[outindex++] & 3) << 6;
0945: element |= (inData[outindex++] & 3) << 4;
0946: element |= (inData[outindex++] & 3) << 2;
0947: element |= (inData[outindex++] & 3);
0948: data[inIndex++] = (byte) element;
0949:
0950: element = (inData[outindex++] & 3) << 6;
0951: element |= (inData[outindex++] & 3) << 4;
0952: element |= (inData[outindex++] & 3) << 2;
0953: element |= (inData[outindex++] & 3);
0954: data[inIndex++] = (byte) element;
0955:
0956: bitnum += 16;
0957: }
0958: break;
0959:
0960: case 4:
0961: for (; i < w - 7; i += 8) {
0962: element = (inData[outindex++] & 0xf) << 4;
0963: element |= (inData[outindex++] & 0xf);
0964: data[inIndex++] = (byte) element;
0965:
0966: element = (inData[outindex++] & 0xf) << 4;
0967: element |= (inData[outindex++] & 0xf);
0968: data[inIndex++] = (byte) element;
0969:
0970: element = (inData[outindex++] & 0xf) << 4;
0971: element |= (inData[outindex++] & 0xf);
0972: data[inIndex++] = (byte) element;
0973:
0974: element = (inData[outindex++] & 0xf) << 4;
0975: element |= (inData[outindex++] & 0xf);
0976: data[inIndex++] = (byte) element;
0977:
0978: bitnum += 32;
0979: }
0980: break;
0981: }
0982:
0983: // Process final portion of scanline
0984: for (; i < w; i++) {
0985: int shift = shiftOffset - (bitnum & 7);
0986:
0987: element = data[index + (bitnum >> 3)];
0988: element &= ~(bitMask << shift);
0989: element |= (inData[outindex++] & bitMask) << shift;
0990: data[index + (bitnum >> 3)] = (byte) element;
0991:
0992: bitnum += pixbits;
0993: }
0994:
0995: index += scanlineStride;
0996: }
0997:
0998: markDirty();
0999: }
1000:
1001: /**
1002: * Returns an int array containing all samples for a rectangle of pixels,
1003: * one sample per array element.
1004: * An ArrayIndexOutOfBoundsException may be thrown
1005: * if the coordinates are not in bounds.
1006: * @param x, y the coordinates of the upper-left pixel location
1007: * @param w Width of the pixel rectangle
1008: * @param h Height of the pixel rectangle
1009: * @param iArray An optionally pre-allocated int array
1010: * @return the samples for the specified rectangle of pixels.
1011: */
1012: public int[] getPixels(int x, int y, int w, int h, int iArray[]) {
1013: if ((x < this .minX) || (y < this .minY) || (x + w > this .maxX)
1014: || (y + h > this .maxY)) {
1015: throw new ArrayIndexOutOfBoundsException(
1016: "Coordinate out of bounds!");
1017: }
1018: if (iArray == null) {
1019: iArray = new int[w * h];
1020: }
1021: int pixbits = pixelBitStride;
1022: int scanbit = dataBitOffset + (x - minX) * pixbits;
1023: int index = (y - minY) * scanlineStride;
1024: int outindex = 0;
1025: byte data[] = this .data;
1026:
1027: for (int j = 0; j < h; j++) {
1028: int bitnum = scanbit;
1029: int element;
1030:
1031: // Process initial portion of scanline
1032: int i = 0;
1033: while ((i < w) && ((bitnum & 7) != 0)) {
1034: int shift = shiftOffset - (bitnum & 7);
1035: iArray[outindex++] = bitMask
1036: & (data[index + (bitnum >> 3)] >> shift);
1037: bitnum += pixbits;
1038: i++;
1039: }
1040:
1041: // Process central portion of scanline 8 pixels at a time
1042: int inIndex = index + (bitnum >> 3);
1043: switch (pixbits) {
1044: case 1:
1045: for (; i < w - 7; i += 8) {
1046: element = data[inIndex++];
1047: iArray[outindex++] = (element >> 7) & 1;
1048: iArray[outindex++] = (element >> 6) & 1;
1049: iArray[outindex++] = (element >> 5) & 1;
1050: iArray[outindex++] = (element >> 4) & 1;
1051: iArray[outindex++] = (element >> 3) & 1;
1052: iArray[outindex++] = (element >> 2) & 1;
1053: iArray[outindex++] = (element >> 1) & 1;
1054: iArray[outindex++] = element & 1;
1055: bitnum += 8;
1056: }
1057: break;
1058:
1059: case 2:
1060: for (; i < w - 7; i += 8) {
1061: element = data[inIndex++];
1062: iArray[outindex++] = (element >> 6) & 3;
1063: iArray[outindex++] = (element >> 4) & 3;
1064: iArray[outindex++] = (element >> 2) & 3;
1065: iArray[outindex++] = element & 3;
1066:
1067: element = data[inIndex++];
1068: iArray[outindex++] = (element >> 6) & 3;
1069: iArray[outindex++] = (element >> 4) & 3;
1070: iArray[outindex++] = (element >> 2) & 3;
1071: iArray[outindex++] = element & 3;
1072:
1073: bitnum += 16;
1074: }
1075: break;
1076:
1077: case 4:
1078: for (; i < w - 7; i += 8) {
1079: element = data[inIndex++];
1080: iArray[outindex++] = (element >> 4) & 0xf;
1081: iArray[outindex++] = element & 0xf;
1082:
1083: element = data[inIndex++];
1084: iArray[outindex++] = (element >> 4) & 0xf;
1085: iArray[outindex++] = element & 0xf;
1086:
1087: element = data[inIndex++];
1088: iArray[outindex++] = (element >> 4) & 0xf;
1089: iArray[outindex++] = element & 0xf;
1090:
1091: element = data[inIndex++];
1092: iArray[outindex++] = (element >> 4) & 0xf;
1093: iArray[outindex++] = element & 0xf;
1094:
1095: bitnum += 32;
1096: }
1097: break;
1098: }
1099:
1100: // Process final portion of scanline
1101: for (; i < w; i++) {
1102: int shift = shiftOffset - (bitnum & 7);
1103: iArray[outindex++] = bitMask
1104: & (data[index + (bitnum >> 3)] >> shift);
1105: bitnum += pixbits;
1106: }
1107:
1108: index += scanlineStride;
1109: }
1110:
1111: return iArray;
1112: }
1113:
1114: /**
1115: * Sets all samples for a rectangle of pixels from an int array containing
1116: * one sample per array element.
1117: * An ArrayIndexOutOfBoundsException may be thrown if the coordinates are
1118: * not in bounds.
1119: * @param x The X coordinate of the upper left pixel location.
1120: * @param y The Y coordinate of the upper left pixel location.
1121: * @param w Width of the pixel rectangle.
1122: * @param h Height of the pixel rectangle.
1123: * @param iArray The input int pixel array.
1124: */
1125: public void setPixels(int x, int y, int w, int h, int iArray[]) {
1126: if ((x < this .minX) || (y < this .minY) || (x + w > this .maxX)
1127: || (y + h > this .maxY)) {
1128: throw new ArrayIndexOutOfBoundsException(
1129: "Coordinate out of bounds!");
1130: }
1131: int pixbits = pixelBitStride;
1132: int scanbit = dataBitOffset + (x - minX) * pixbits;
1133: int index = (y - minY) * scanlineStride;
1134: int outindex = 0;
1135: byte data[] = this .data;
1136: for (int j = 0; j < h; j++) {
1137: int bitnum = scanbit;
1138: int element;
1139:
1140: // Process initial portion of scanline
1141: int i = 0;
1142: while ((i < w) && ((bitnum & 7) != 0)) {
1143: int shift = shiftOffset - (bitnum & 7);
1144: element = data[index + (bitnum >> 3)];
1145: element &= ~(bitMask << shift);
1146: element |= (iArray[outindex++] & bitMask) << shift;
1147: data[index + (bitnum >> 3)] = (byte) element;
1148:
1149: bitnum += pixbits;
1150: i++;
1151: }
1152:
1153: // Process central portion of scanline 8 pixels at a time
1154: int inIndex = index + (bitnum >> 3);
1155: switch (pixbits) {
1156: case 1:
1157: for (; i < w - 7; i += 8) {
1158: element = (iArray[outindex++] & 1) << 7;
1159: element |= (iArray[outindex++] & 1) << 6;
1160: element |= (iArray[outindex++] & 1) << 5;
1161: element |= (iArray[outindex++] & 1) << 4;
1162: element |= (iArray[outindex++] & 1) << 3;
1163: element |= (iArray[outindex++] & 1) << 2;
1164: element |= (iArray[outindex++] & 1) << 1;
1165: element |= (iArray[outindex++] & 1);
1166: data[inIndex++] = (byte) element;
1167:
1168: bitnum += 8;
1169: }
1170: break;
1171:
1172: case 2:
1173: for (; i < w - 7; i += 8) {
1174: element = (iArray[outindex++] & 3) << 6;
1175: element |= (iArray[outindex++] & 3) << 4;
1176: element |= (iArray[outindex++] & 3) << 2;
1177: element |= (iArray[outindex++] & 3);
1178: data[inIndex++] = (byte) element;
1179:
1180: element = (iArray[outindex++] & 3) << 6;
1181: element |= (iArray[outindex++] & 3) << 4;
1182: element |= (iArray[outindex++] & 3) << 2;
1183: element |= (iArray[outindex++] & 3);
1184: data[inIndex++] = (byte) element;
1185:
1186: bitnum += 16;
1187: }
1188: break;
1189:
1190: case 4:
1191: for (; i < w - 7; i += 8) {
1192: element = (iArray[outindex++] & 0xf) << 4;
1193: element |= (iArray[outindex++] & 0xf);
1194: data[inIndex++] = (byte) element;
1195:
1196: element = (iArray[outindex++] & 0xf) << 4;
1197: element |= (iArray[outindex++] & 0xf);
1198: data[inIndex++] = (byte) element;
1199:
1200: element = (iArray[outindex++] & 0xf) << 4;
1201: element |= (iArray[outindex++] & 0xf);
1202: data[inIndex++] = (byte) element;
1203:
1204: element = (iArray[outindex++] & 0xf) << 4;
1205: element |= (iArray[outindex++] & 0xf);
1206: data[inIndex++] = (byte) element;
1207:
1208: bitnum += 32;
1209: }
1210: break;
1211: }
1212:
1213: // Process final portion of scanline
1214: for (; i < w; i++) {
1215: int shift = shiftOffset - (bitnum & 7);
1216:
1217: element = data[index + (bitnum >> 3)];
1218: element &= ~(bitMask << shift);
1219: element |= (iArray[outindex++] & bitMask) << shift;
1220: data[index + (bitnum >> 3)] = (byte) element;
1221:
1222: bitnum += pixbits;
1223: }
1224:
1225: index += scanlineStride;
1226: }
1227:
1228: markDirty();
1229: }
1230:
1231: /**
1232: * Creates a subraster given a region of the raster. The x and y
1233: * coordinates specify the horizontal and vertical offsets
1234: * from the upper-left corner of this raster to the upper-left corner
1235: * of the subraster. Note that the subraster will reference the same
1236: * DataBuffer as the parent raster, but using different offsets. The
1237: * bandList is ignored.
1238: * @param x X offset.
1239: * @param y Y offset.
1240: * @param width Width (in pixels) of the subraster.
1241: * @param height Height (in pixels) of the subraster.
1242: * @param x0 Translated X origin of the subraster.
1243: * @param y0 Translated Y origin of the subraster.
1244: * @param bandList Array of band indices.
1245: * @exception RasterFormatException
1246: * if the specified bounding box is outside of the parent raster.
1247: */
1248: public Raster createChild(int x, int y, int width, int height,
1249: int x0, int y0, int[] bandList) {
1250: WritableRaster newRaster = createWritableChild(x, y, width,
1251: height, x0, y0, bandList);
1252: return (Raster) newRaster;
1253: }
1254:
1255: /**
1256: * Creates a Writable subRaster given a region of the Raster. The x and y
1257: * coordinates specify the horizontal and vertical offsets
1258: * from the upper-left corner of this Raster to the upper-left corner
1259: * of the subRaster. The bandList is ignored.
1260: * A translation to the subRaster may also be specified.
1261: * Note that the subRaster will reference the same
1262: * DataBuffer as the parent Raster, but using different offsets.
1263: * @param x X offset.
1264: * @param y Y offset.
1265: * @param width Width (in pixels) of the subraster.
1266: * @param height Height (in pixels) of the subraster.
1267: * @param x0 Translated X origin of the subraster.
1268: * @param y0 Translated Y origin of the subraster.
1269: * @param bandList Array of band indices.
1270: * @exception RasterFormatException
1271: * if the specified bounding box is outside of the parent Raster.
1272: */
1273: public WritableRaster createWritableChild(int x, int y, int width,
1274: int height, int x0, int y0, int[] bandList) {
1275: if (x < this .minX) {
1276: throw new RasterFormatException("x lies outside the raster");
1277: }
1278: if (y < this .minY) {
1279: throw new RasterFormatException("y lies outside the raster");
1280: }
1281: if ((x + width < x) || (x + width > this .minX + this .width)) {
1282: throw new RasterFormatException(
1283: "(x + width) is outside of Raster");
1284: }
1285: if ((y + height < y) || (y + height > this .minY + this .height)) {
1286: throw new RasterFormatException(
1287: "(y + height) is outside of Raster");
1288: }
1289:
1290: SampleModel sm;
1291:
1292: if (bandList != null) {
1293: sm = sampleModel.createSubsetSampleModel(bandList);
1294: } else {
1295: sm = sampleModel;
1296: }
1297:
1298: int deltaX = x0 - x;
1299: int deltaY = y0 - y;
1300:
1301: return new BytePackedRaster(sm, dataBuffer, new Rectangle(x0,
1302: y0, width, height), new Point(sampleModelTranslateX
1303: + deltaX, sampleModelTranslateY + deltaY), this );
1304: }
1305:
1306: /**
1307: * Creates a raster with the same layout but using a different
1308: * width and height, and with new zeroed data arrays.
1309: */
1310: public WritableRaster createCompatibleWritableRaster(int w, int h) {
1311: if (w <= 0 || h <= 0) {
1312: throw new RasterFormatException("negative "
1313: + ((w <= 0) ? "width" : "height"));
1314: }
1315:
1316: SampleModel sm = sampleModel.createCompatibleSampleModel(w, h);
1317:
1318: return new BytePackedRaster(sm, new Point(0, 0));
1319: }
1320:
1321: /**
1322: * Creates a raster with the same layout and the same
1323: * width and height, and with new zeroed data arrays.
1324: */
1325: public WritableRaster createCompatibleWritableRaster() {
1326: return createCompatibleWritableRaster(width, height);
1327: }
1328:
1329: /**
1330: * Verify that the layout parameters are consistent with
1331: * the data. If strictCheck
1332: * is false, this method will check for ArrayIndexOutOfBounds conditions.
1333: * If strictCheck is true, this method will check for additional error
1334: * conditions such as line wraparound (width of a line greater than
1335: * the scanline stride).
1336: * @return String Error string, if the layout is incompatible with
1337: * the data. Otherwise returns null.
1338: */
1339: private void verify(boolean strictCheck) {
1340: // Make sure data for Raster is in a legal range
1341: if (dataBitOffset < 0) {
1342: throw new RasterFormatException("Data offsets must be >= 0");
1343: }
1344:
1345: int lastbit = (dataBitOffset + (height - 1) * scanlineStride
1346: * 8 + (width - 1) * pixelBitStride + pixelBitStride - 1);
1347: if (lastbit / 8 >= data.length) {
1348: throw new RasterFormatException(
1349: "raster dimensions overflow " + "array bounds");
1350: }
1351: if (strictCheck) {
1352: if (height > 1) {
1353: lastbit = width * pixelBitStride - 1;
1354: if (lastbit / 8 >= scanlineStride) {
1355: throw new RasterFormatException("data for adjacent"
1356: + " scanlines overlaps");
1357: }
1358: }
1359: }
1360: }
1361:
1362: public String toString() {
1363: return new String("BytePackedRaster: width = " + width
1364: + " height = " + height + " #channels " + numBands
1365: + " xOff = " + sampleModelTranslateX + " yOff = "
1366: + sampleModelTranslateY);
1367: }
1368: }
|