GNU Classpath (0.95) | |
Frames | No Frames |
1: /* Copyright (C) 2000, 2002, 2003, 2004, 2006, Free Software Foundation 2: 3: This file is part of GNU Classpath. 4: 5: GNU Classpath is free software; you can redistribute it and/or modify 6: it under the terms of the GNU General Public License as published by 7: the Free Software Foundation; either version 2, or (at your option) 8: any later version. 9: 10: GNU Classpath is distributed in the hope that it will be useful, but 11: WITHOUT ANY WARRANTY; without even the implied warranty of 12: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13: General Public License for more details. 14: 15: You should have received a copy of the GNU General Public License 16: along with GNU Classpath; see the file COPYING. If not, write to the 17: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 18: 02110-1301 USA. 19: 20: Linking this library statically or dynamically with other modules is 21: making a combined work based on this library. Thus, the terms and 22: conditions of the GNU General Public License cover the whole 23: combination. 24: 25: As a special exception, the copyright holders of this library give you 26: permission to link this library with independent modules to produce an 27: executable, regardless of the license terms of these independent 28: modules, and to copy and distribute the resulting executable under 29: terms of your choice, provided that you also meet, for each linked 30: independent module, the terms and conditions of the license of that 31: module. An independent module is a module which is not derived from 32: or based on this library. If you modify this library, you may extend 33: this exception to your version of the library, but you are not 34: obligated to do so. If you do not wish to do so, delete this 35: exception statement from your version. */ 36: 37: package java.awt.image; 38: 39: import java.util.Arrays; 40: 41: import gnu.java.awt.BitMaskExtent; 42: 43: /** 44: * A <code>SampleModel</code> used when all samples are stored in a single 45: * data element in the {@link DataBuffer}, and each data element contains 46: * samples for one pixel only. 47: * 48: * @author Rolf W. Rasmussen (rolfwr@ii.uib.no) 49: */ 50: public class SinglePixelPackedSampleModel extends SampleModel 51: { 52: private int scanlineStride; 53: private int[] bitMasks; 54: private int[] bitOffsets; 55: private int[] sampleSize; 56: 57: /** 58: * Creates a new <code>SinglePixelPackedSampleModel</code>. 59: * 60: * @param dataType the data buffer type. 61: * @param w the width (in pixels). 62: * @param h the height (in pixels). 63: * @param bitMasks an array containing the bit mask used to extract the 64: * sample value for each band. 65: */ 66: public SinglePixelPackedSampleModel(int dataType, int w, int h, 67: int[] bitMasks) 68: { 69: this(dataType, w, h, w, bitMasks); 70: } 71: 72: /** 73: * Creates a new <code>SinglePixelPackedSampleModel</code>. 74: * 75: * @param dataType the data buffer type. 76: * @param w the width (in pixels). 77: * @param h the height (in pixels). 78: * @param scanlineStride the number of data elements between a pixel on one 79: * row and the corresponding pixel on the next row. 80: * @param bitMasks an array containing the bit mask used to extract the 81: * sample value for each band. 82: */ 83: public SinglePixelPackedSampleModel(int dataType, int w, int h, 84: int scanlineStride, int[] bitMasks) 85: { 86: super(dataType, w, h, bitMasks.length); 87: 88: switch (dataType) 89: { 90: case DataBuffer.TYPE_BYTE: 91: case DataBuffer.TYPE_USHORT: 92: case DataBuffer.TYPE_INT: 93: break; 94: default: 95: throw new IllegalArgumentException( 96: "SinglePixelPackedSampleModel unsupported dataType"); 97: } 98: 99: this.scanlineStride = scanlineStride; 100: this.bitMasks = bitMasks; 101: 102: bitOffsets = new int[numBands]; 103: sampleSize = new int[numBands]; 104: 105: BitMaskExtent extent = new BitMaskExtent(); 106: for (int b = 0; b < numBands; b++) 107: { 108: // the mask is an unsigned integer 109: long mask = bitMasks[b] & 0xFFFFFFFFL; 110: extent.setMask(mask); 111: sampleSize[b] = extent.bitWidth; 112: bitOffsets[b] = extent.leastSignificantBit; 113: } 114: } 115: 116: /** 117: * Returns the number of data elements. 118: * 119: * @return <code>1</code>. 120: */ 121: public int getNumDataElements() 122: { 123: return 1; 124: } 125: 126: /** 127: * Creates a new <code>SampleModel</code> that is compatible with this 128: * model and has the specified width and height. 129: * 130: * @param w the width (in pixels). 131: * @param h the height (in pixels). 132: * 133: * @return The new sample model. 134: */ 135: public SampleModel createCompatibleSampleModel(int w, int h) 136: { 137: /* FIXME: We can avoid recalculation of bit offsets and sample 138: sizes here by passing these from the current instance to a 139: special private constructor. */ 140: return new SinglePixelPackedSampleModel(dataType, w, h, bitMasks); 141: } 142: 143: 144: /** 145: * Creates a DataBuffer for holding pixel data in the format and 146: * layout described by this SampleModel. The returned buffer will 147: * consist of one single bank. 148: * 149: * @return The data buffer. 150: */ 151: public DataBuffer createDataBuffer() 152: { 153: // We can save (scanlineStride - width) pixels at the very end of 154: // the buffer. The Sun reference implementation (J2SE 1.3.1 and 155: // 1.4.1_01) seems to do this; tested with Mauve test code. 156: int size = scanlineStride * (height - 1) + width; 157: 158: DataBuffer buffer = null; 159: switch (getTransferType()) 160: { 161: case DataBuffer.TYPE_BYTE: 162: buffer = new DataBufferByte(size); 163: break; 164: case DataBuffer.TYPE_USHORT: 165: buffer = new DataBufferUShort(size); 166: break; 167: case DataBuffer.TYPE_INT: 168: buffer = new DataBufferInt(size); 169: break; 170: } 171: return buffer; 172: } 173: 174: /** 175: * Returns an array containing the size (in bits) for each band accessed by 176: * the <code>SampleModel</code>. 177: * 178: * @return An array. 179: * 180: * @see #getSampleSize(int) 181: */ 182: public int[] getSampleSize() 183: { 184: return (int[]) sampleSize.clone(); 185: } 186: 187: /** 188: * Returns the size (in bits) of the samples for the specified band. 189: * 190: * @param band the band (in the range <code>0</code> to 191: * <code>getNumBands() - 1</code>). 192: * 193: * @return The sample size (in bits). 194: */ 195: public int getSampleSize(int band) 196: { 197: return sampleSize[band]; 198: } 199: 200: /** 201: * Returns the index in the data buffer that stores the pixel at (x, y). 202: * 203: * @param x the x-coordinate. 204: * @param y the y-coordinate. 205: * 206: * @return The index in the data buffer that stores the pixel at (x, y). 207: */ 208: public int getOffset(int x, int y) 209: { 210: return scanlineStride*y + x; 211: } 212: 213: public int[] getBitOffsets() 214: { 215: return bitOffsets; 216: } 217: 218: public int[] getBitMasks() 219: { 220: return bitMasks; 221: } 222: 223: /** 224: * Returns the number of data elements from a pixel in one row to the 225: * corresponding pixel in the next row. 226: * 227: * @return The scanline stride. 228: */ 229: public int getScanlineStride() 230: { 231: return scanlineStride; 232: } 233: 234: /** 235: * Creates a new <code>SinglePixelPackedSampleModel</code> that accesses 236: * the specified subset of bands. 237: * 238: * @param bands an array containing band indices (<code>null</code> not 239: * permitted). 240: * 241: * @return A new sample model. 242: * 243: * @throws NullPointerException if <code>bands</code> is <code>null</code>. 244: * @throws RasterFormatException if <code>bands.length</code> is greater 245: * than the number of bands in this model. 246: */ 247: public SampleModel createSubsetSampleModel(int[] bands) 248: { 249: if (bands.length > numBands) 250: throw new RasterFormatException("Too many bands."); 251: 252: int numBands = bands.length; 253: 254: int[] bitMasks = new int[numBands]; 255: 256: for (int b = 0; b < numBands; b++) 257: bitMasks[b] = this.bitMasks[bands[b]]; 258: 259: return new SinglePixelPackedSampleModel(dataType, width, height, 260: scanlineStride, bitMasks); 261: } 262: 263: public Object getDataElements(int x, int y, Object obj, 264: DataBuffer data) 265: { 266: int type = getTransferType(); 267: Object ret = null; 268: switch (type) 269: { 270: case DataBuffer.TYPE_BYTE: 271: { 272: byte[] in = (byte[]) obj; 273: if (in == null) 274: in = new byte[1]; 275: in[0] = (byte) data.getElem(x + y * scanlineStride); 276: ret = in; 277: } 278: break; 279: case DataBuffer.TYPE_USHORT: 280: { 281: short[] in = (short[]) obj; 282: if (in == null) 283: in = new short[1]; 284: in[0] = (short) data.getElem(x + y * scanlineStride); 285: ret = in; 286: } 287: break; 288: case DataBuffer.TYPE_INT: 289: { 290: int[] in = (int[]) obj; 291: if (in == null) 292: in = new int[1]; 293: in[0] = data.getElem(x + y * scanlineStride); 294: ret = in; 295: } 296: break; 297: } 298: return ret; 299: } 300: 301: /** 302: * Returns an array containing the samples for the pixel at (x, y) in the 303: * specified data buffer. If <code>iArray</code> is not <code>null</code>, 304: * it will be populated with the sample values and returned as the result of 305: * this function (this avoids allocating a new array instance). 306: * 307: * @param x the x-coordinate of the pixel. 308: * @param y the y-coordinate of the pixel. 309: * @param iArray an array to populate with the sample values and return as 310: * the result (if <code>null</code>, a new array will be allocated). 311: * @param data the data buffer (<code>null</code> not permitted). 312: * 313: * @return The pixel sample values. 314: * 315: * @throws NullPointerException if <code>data</code> is <code>null</code>. 316: */ 317: public int[] getPixel(int x, int y, int[] iArray, DataBuffer data) 318: { 319: int offset = scanlineStride*y + x; 320: if (iArray == null) iArray = new int[numBands]; 321: int samples = data.getElem(offset); 322: 323: for (int b = 0; b < numBands; b++) 324: iArray[b] = (samples & bitMasks[b]) >>> bitOffsets[b]; 325: 326: return iArray; 327: } 328: 329: /** 330: * Returns an array containing the samples for the pixels in the region 331: * specified by (x, y, w, h) in the specified data buffer. The array is 332: * ordered by pixels (that is, all the samples for the first pixel are 333: * grouped together, followed by all the samples for the second pixel, and so 334: * on). If <code>iArray</code> is not <code>null</code>, it will be 335: * populated with the sample values and returned as the result of this 336: * function (this avoids allocating a new array instance). 337: * 338: * @param x the x-coordinate of the top-left pixel. 339: * @param y the y-coordinate of the top-left pixel. 340: * @param w the width of the region of pixels. 341: * @param h the height of the region of pixels. 342: * @param iArray an array to populate with the sample values and return as 343: * the result (if <code>null</code>, a new array will be allocated). 344: * @param data the data buffer (<code>null</code> not permitted). 345: * 346: * @return The pixel sample values. 347: * 348: * @throws NullPointerException if <code>data</code> is <code>null</code>. 349: */ 350: public int[] getPixels(int x, int y, int w, int h, int[] iArray, 351: DataBuffer data) 352: { 353: int offset = scanlineStride*y + x; 354: if (iArray == null) iArray = new int[numBands*w*h]; 355: int outOffset = 0; 356: for (y = 0; y < h; y++) 357: { 358: int lineOffset = offset; 359: for (x = 0; x < w; x++) 360: { 361: int samples = data.getElem(lineOffset++); 362: for (int b = 0; b < numBands; b++) 363: iArray[outOffset++] = (samples & bitMasks[b]) >>> bitOffsets[b]; 364: } 365: offset += scanlineStride; 366: } 367: return iArray; 368: } 369: 370: /** 371: * Returns the sample value for the pixel at (x, y) in the specified data 372: * buffer. 373: * 374: * @param x the x-coordinate of the pixel. 375: * @param y the y-coordinate of the pixel. 376: * @param b the band (in the range <code>0</code> to 377: * <code>getNumBands() - 1</code>). 378: * @param data the data buffer (<code>null</code> not permitted). 379: * 380: * @return The sample value. 381: * 382: * @throws NullPointerException if <code>data</code> is <code>null</code>. 383: */ 384: public int getSample(int x, int y, int b, DataBuffer data) 385: { 386: int offset = scanlineStride*y + x; 387: int samples = data.getElem(offset); 388: return (samples & bitMasks[b]) >>> bitOffsets[b]; 389: } 390: 391: public void setDataElements(int x, int y, Object obj, DataBuffer data) 392: { 393: int transferType = getTransferType(); 394: switch (transferType) 395: { 396: case DataBuffer.TYPE_BYTE: 397: { 398: byte[] in = (byte[]) obj; 399: data.setElem(y * scanlineStride + x, ((int) in[0]) & 0xff); 400: } 401: break; 402: case DataBuffer.TYPE_USHORT: 403: { 404: short[] in = (short[]) obj; 405: data.setElem(y * scanlineStride + x, ((int) in[0]) & 0xffff); 406: } 407: break; 408: case DataBuffer.TYPE_INT: 409: { 410: int[] in = (int[]) obj; 411: data.setElem(y * scanlineStride + x, in[0]); 412: break; 413: } 414: } 415: } 416: 417: /** 418: * Sets the samples for the pixel at (x, y) in the specified data buffer to 419: * the specified values. 420: * 421: * @param x the x-coordinate of the pixel. 422: * @param y the y-coordinate of the pixel. 423: * @param iArray the sample values (<code>null</code> not permitted). 424: * @param data the data buffer (<code>null</code> not permitted). 425: * 426: * @throws NullPointerException if either <code>iArray</code> or 427: * <code>data</code> is <code>null</code>. 428: */ 429: public void setPixel(int x, int y, int[] iArray, DataBuffer data) 430: { 431: int offset = scanlineStride*y + x; 432: 433: int samples = 0; 434: for (int b = 0; b < numBands; b++) 435: samples |= (iArray[b] << bitOffsets[b]) & bitMasks[b]; 436: 437: data.setElem(offset, samples); 438: } 439: 440: /** 441: * This method implements a more efficient way to set pixels than the default 442: * implementation of the super class. It copies the pixel components directly 443: * from the input array instead of creating a intermediate buffer. 444: * @param x The x-coordinate of the pixel rectangle in <code>obj</code>. 445: * @param y The y-coordinate of the pixel rectangle in <code>obj</code>. 446: * @param w The width of the pixel rectangle in <code>obj</code>. 447: * @param h The height of the pixel rectangle in <code>obj</code>. 448: * @param iArray The primitive array containing the pixels to set. 449: * @param data The DataBuffer to store the pixels into. 450: * @see java.awt.image.SampleModel#setPixels(int, int, int, int, int[], 451: * java.awt.image.DataBuffer) 452: */ 453: public void setPixels(int x, int y, int w, int h, int[] iArray, 454: DataBuffer data) 455: { 456: int inOffset = 0; 457: for (int yy=y; yy<(y+h); yy++) 458: { 459: int offset = scanlineStride*yy + x; 460: for (int xx=x; xx<(x+w); xx++) 461: { 462: int samples = 0; 463: for (int b = 0; b < numBands; b++) 464: samples |= (iArray[inOffset+b] << bitOffsets[b]) & bitMasks[b]; 465: data.setElem(0, offset, samples); 466: inOffset += numBands; 467: offset += 1; 468: } 469: } 470: } 471: 472: /** 473: * Sets the sample value for a band for the pixel at (x, y) in the 474: * specified data buffer. 475: * 476: * @param x the x-coordinate of the pixel. 477: * @param y the y-coordinate of the pixel. 478: * @param b the band (in the range <code>0</code> to 479: * <code>getNumBands() - 1</code>). 480: * @param s the sample value. 481: * @param data the data buffer (<code>null</code> not permitted). 482: * 483: * @throws NullPointerException if <code>data</code> is <code>null</code>. 484: */ 485: public void setSample(int x, int y, int b, int s, DataBuffer data) 486: { 487: int offset = scanlineStride*y + x; 488: int samples = data.getElem(offset); 489: int bitMask = bitMasks[b]; 490: samples &= ~bitMask; 491: samples |= (s << bitOffsets[b]) & bitMask; 492: data.setElem(offset, samples); 493: } 494: 495: /** 496: * Tests this sample model for equality with an arbitrary object. This 497: * method returns <code>true</code> if and only if: 498: * <ul> 499: * <li><code>obj</code> is not <code>null</code>; 500: * <li><code>obj</code> is an instance of 501: * <code>SinglePixelPackedSampleModel</code>; 502: * <li>both models have the same: 503: * <ul> 504: * <li><code>dataType</code>; 505: * <li><code>width</code>; 506: * <li><code>height</code>; 507: * <li><code>numBands</code>; 508: * <li><code>scanlineStride</code>; 509: * <li><code>bitMasks</code>; 510: * <li><code>bitOffsets</code>. 511: * </ul> 512: * </li> 513: * </ul> 514: * 515: * @param obj the object (<code>null</code> permitted) 516: * 517: * @return <code>true</code> if this model is equal to <code>obj</code>, and 518: * <code>false</code> otherwise. 519: */ 520: public boolean equals(Object obj) 521: { 522: if (this == obj) 523: return true; 524: if (! (obj instanceof SinglePixelPackedSampleModel)) 525: return false; 526: SinglePixelPackedSampleModel that = (SinglePixelPackedSampleModel) obj; 527: if (this.dataType != that.dataType) 528: return false; 529: if (this.width != that.width) 530: return false; 531: if (this.height != that.height) 532: return false; 533: if (this.numBands != that.numBands) 534: return false; 535: if (this.scanlineStride != that.scanlineStride) 536: return false; 537: if (!Arrays.equals(this.bitMasks, that.bitMasks)) 538: return false; 539: if (!Arrays.equals(this.bitOffsets, that.bitOffsets)) 540: return false; 541: return true; 542: } 543: 544: /** 545: * Returns a hash code for this <code>SinglePixelPackedSampleModel</code>. 546: * 547: * @return A hash code. 548: */ 549: public int hashCode() 550: { 551: // this hash code won't match Sun's, but that shouldn't matter... 552: int result = 193; 553: result = 37 * result + dataType; 554: result = 37 * result + width; 555: result = 37 * result + height; 556: result = 37 * result + numBands; 557: result = 37 * result + scanlineStride; 558: for (int i = 0; i < bitMasks.length; i++) 559: result = 37 * result + bitMasks[i]; 560: for (int i = 0; i < bitOffsets.length; i++) 561: result = 37 * result + bitOffsets[i]; 562: return result; 563: } 564: 565: /** 566: * Creates a String with some information about this SampleModel. 567: * @return A String describing this SampleModel. 568: * @see java.lang.Object#toString() 569: */ 570: public String toString() 571: { 572: StringBuffer result = new StringBuffer(); 573: result.append(getClass().getName()); 574: result.append("["); 575: result.append("scanlineStride=").append(scanlineStride); 576: for(int i = 0; i < bitMasks.length; i+=1) 577: { 578: result.append(", mask[").append(i).append("]=0x").append( 579: Integer.toHexString(bitMasks[i])); 580: } 581: 582: result.append("]"); 583: return result.toString(); 584: } 585: }
GNU Classpath (0.95) |