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