Source for java.awt.image.SinglePixelPackedSampleModel

   1: /* Copyright (C) 2000, 2002, 2003, 2004  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 gnu.java.awt.BitMaskExtent;
  40: import gnu.java.awt.Buffers;
  41: 
  42: /**
  43:  * @author Rolf W. Rasmussen (rolfwr@ii.uib.no)
  44:  */
  45: public class SinglePixelPackedSampleModel extends SampleModel
  46: {
  47:   private int scanlineStride;
  48:   private int[] bitMasks;
  49:   private int[] bitOffsets;
  50:   private int[] sampleSize;
  51:   
  52:   public SinglePixelPackedSampleModel(int dataType, int w, int h,
  53:                       int[] bitMasks)
  54:   {
  55:     this(dataType, w, h, w, bitMasks);
  56:   }
  57: 
  58:   public SinglePixelPackedSampleModel(int dataType, int w, int h,
  59:                       int scanlineStride, int[] bitMasks)
  60:   {
  61:     super(dataType, w, h, bitMasks.length);
  62: 
  63:     switch (dataType)
  64:       {
  65:       case DataBuffer.TYPE_BYTE:
  66:       case DataBuffer.TYPE_USHORT:
  67:       case DataBuffer.TYPE_INT:
  68:     break;
  69:       default:
  70:     throw new IllegalArgumentException("SinglePixelPackedSampleModel unsupported dataType");
  71:       }
  72:     
  73:     this.scanlineStride = scanlineStride;
  74:     this.bitMasks = bitMasks;
  75:     
  76:     bitOffsets = new int[numBands];
  77:     sampleSize = new int[numBands];
  78:     
  79:     BitMaskExtent extent = new BitMaskExtent();
  80:     for (int b=0; b<numBands; b++)
  81:       {
  82:     extent.setMask(bitMasks[b]);
  83:     sampleSize[b] = extent.bitWidth;
  84:     bitOffsets[b] = extent.leastSignificantBit;
  85:       }
  86:   }
  87: 
  88:   public int getNumDataElements()
  89:   {
  90:     return 1;
  91:   }
  92: 
  93:   public SampleModel createCompatibleSampleModel(int w, int h)
  94:   {
  95:     /* FIXME: We can avoid recalculation of bit offsets and sample
  96:        sizes here by passing these from the current instance to a
  97:        special private constructor. */
  98:     return new SinglePixelPackedSampleModel(dataType, w, h, bitMasks);
  99:   }
 100: 
 101: 
 102:   /**
 103:    * Creates a DataBuffer for holding pixel data in the format and
 104:    * layout described by this SampleModel. The returned buffer will
 105:    * consist of one single bank.
 106:    */
 107:   public DataBuffer createDataBuffer()
 108:   {
 109:     int size;
 110: 
 111:     // We can save (scanlineStride - width) pixels at the very end of
 112:     // the buffer. The Sun reference implementation (J2SE 1.3.1 and
 113:     // 1.4.1_01) seems to do this; tested with Mauve test code.
 114:     size = scanlineStride * (height - 1) + width;
 115: 
 116:     return Buffers.createBuffer(getDataType(), size);
 117:   }
 118: 
 119: 
 120:   public int[] getSampleSize()
 121:   {
 122:     return sampleSize;
 123:   }
 124:   
 125:   public int getSampleSize(int band)
 126:   {
 127:     return sampleSize[band];
 128:   }
 129: 
 130:   public int getOffset(int x, int y)
 131:   {
 132:     return scanlineStride*y + x;
 133:   }
 134: 
 135:   public int[] getBitOffsets()
 136:   {
 137:     return bitOffsets;
 138:   }
 139: 
 140:   public int[] getBitMasks()
 141:   {
 142:     return bitMasks;
 143:   }
 144: 
 145:   public int getScanlineStride()
 146:   {
 147:     return scanlineStride;
 148:   }
 149: 
 150:   public SampleModel createSubsetSampleModel(int[] bands)
 151:   {
 152:     // FIXME: Is this the right way to interpret bands?
 153:     
 154:     int numBands = bands.length;
 155:     
 156:     int[] bitMasks = new int[numBands];
 157: 
 158:     for (int b=0; b<numBands; b++)
 159:       bitMasks[b] = this.bitMasks[bands[b]];
 160: 
 161:     return new SinglePixelPackedSampleModel(dataType, width, height,
 162:                         scanlineStride, bitMasks);
 163:   }
 164: 
 165:   public Object getDataElements(int x, int y, Object obj,
 166:                 DataBuffer data)
 167:   {
 168:     int offset = scanlineStride*y + x + data.getOffset();
 169:     
 170:     return Buffers.getData(data, offset, obj,
 171:                0, // destination offset,
 172:                1  // length
 173:                );
 174:   }
 175:   
 176:   /**
 177:    * This is a more efficient implementation of the default implementation in the super
 178:    * class. 
 179:    * @param x The x-coordinate of the pixel rectangle to store in <code>obj</code>.
 180:    * @param y The y-coordinate of the pixel rectangle to store in <code>obj</code>.
 181:    * @param w The width of the pixel rectangle to store in <code>obj</code>.
 182:    * @param h The height of the pixel rectangle to store in <code>obj</code>.
 183:    * @param obj The primitive array to store the pixels into or null to force creation.
 184:    * @param data The DataBuffer that is the source of the pixel data.
 185:    * @return The primitive array containing the pixel data.
 186:    * @see java.awt.image.SampleModel#getDataElements(int, int, int, int, java.lang.Object, java.awt.image.DataBuffer)
 187:    */
 188:   public Object getDataElements(int x, int y, int w, int h, Object obj,
 189:                             DataBuffer data)
 190:   {
 191:     int size = w*h;
 192:     int dataSize = size;
 193:     Object pixelData = null;
 194:     switch (getTransferType())
 195:     {
 196:       case DataBuffer.TYPE_BYTE:
 197:         pixelData = ((DataBufferByte) data).getData();
 198:         if (obj == null) obj = new byte[dataSize];
 199:         break;
 200:        case DataBuffer.TYPE_USHORT:
 201:          pixelData = ((DataBufferUShort) data).getData();
 202:          if (obj == null) obj = new short[dataSize];
 203:          break;
 204:         case DataBuffer.TYPE_INT:
 205:           pixelData = ((DataBufferInt) data).getData();
 206:           if (obj == null) obj = new int[dataSize];
 207:           break;
 208:          default:
 209:              // Seems like the only sensible thing to do.
 210:            throw new ClassCastException();
 211:       }
 212:       if(x==0 && scanlineStride == w)
 213:       { 
 214:         // The full width need to be copied therefore we can copy in one shot.
 215:         System.arraycopy(pixelData, scanlineStride*y + data.getOffset(), obj, 0, size);
 216:       }
 217:       else
 218:       {  
 219:         // Since we do not need the full width we need to copy line by line.
 220:         int outOffset = 0;
 221:         int dataOffset = scanlineStride*y + x + data.getOffset();
 222:         for (int yy = y; yy<(y+h); yy++)
 223:         {
 224:           System.arraycopy(pixelData, dataOffset, obj, outOffset, w);
 225:           dataOffset += scanlineStride;
 226:           outOffset += w;
 227:         }
 228:       }
 229:     return obj;
 230:   }
 231:   
 232: 
 233:   public int[] getPixel(int x, int y, int[] iArray, DataBuffer data)
 234:   {
 235:     int offset = scanlineStride*y + x;
 236:     if (iArray == null) iArray = new int[numBands];
 237:     int samples = data.getElem(offset);
 238: 
 239:     for (int b=0; b<numBands; b++)
 240:       iArray[b] = (samples & bitMasks[b]) >>> bitOffsets[b];
 241:     
 242:     return iArray;
 243:   }
 244: 
 245:   public int[] getPixels(int x, int y, int w, int h, int[] iArray,
 246:              DataBuffer data)
 247:   {
 248:     int offset = scanlineStride*y + x;
 249:     if (iArray == null) iArray = new int[numBands*w*h];
 250:     int outOffset = 0;
 251:     for (y=0; y<h; y++)
 252:       {
 253:     int lineOffset = offset;
 254:     for (x=0; x<w; x++)
 255:       {
 256:         int samples = data.getElem(lineOffset++);
 257:         for (int b=0; b<numBands; b++)
 258:           iArray[outOffset++] = (samples & bitMasks[b]) >>> bitOffsets[b];
 259:       }
 260:     offset += scanlineStride;
 261:       }
 262:     return iArray;    
 263:   }
 264: 
 265:   public int getSample(int x, int y, int b, DataBuffer data)
 266:   {
 267:     int offset = scanlineStride*y + x;
 268:     int samples = data.getElem(offset);
 269:     return (samples & bitMasks[b]) >>> bitOffsets[b];
 270:   }
 271:   
 272:   /**
 273:    * This method implements a more efficient way to set data elements than the default
 274:    * implementation of the super class. It sets the data elements line by line instead 
 275:    * of pixel by pixel.
 276:    * @param x The x-coordinate of the data elements in <code>obj</code>.
 277:    * @param y The y-coordinate of the data elements in <code>obj</code>.
 278:    * @param w The width of the data elements in <code>obj</code>.
 279:    * @param h The height of the data elements in <code>obj</code>.
 280:    * @param obj The primitive array containing the data elements to set.
 281:    * @param data The DataBuffer to store the data elements into.
 282:    * @see java.awt.image.SampleModel#setDataElements(int, int, int, int, java.lang.Object, java.awt.image.DataBuffer)
 283:    */
 284:   public void setDataElements(int x, int y, int w, int h,
 285:                 Object obj, DataBuffer data)
 286:   {
 287:     
 288:     Object pixelData;
 289:     switch (getTransferType())
 290:     {
 291:       case DataBuffer.TYPE_BYTE:
 292:         pixelData = ((DataBufferByte) data).getData();
 293:         break;
 294:        case DataBuffer.TYPE_USHORT:
 295:          pixelData = ((DataBufferUShort) data).getData();
 296:          break;
 297:        case DataBuffer.TYPE_INT:
 298:          pixelData = ((DataBufferInt) data).getData();
 299:          break;
 300:        default:
 301:           // Seems like the only sensible thing to do.
 302:           throw new ClassCastException();
 303:     }
 304:     
 305:     int inOffset = 0;
 306:     int dataOffset = scanlineStride*y + x + data.getOffset();
 307:     for (int yy=y; yy<(y+h); yy++)
 308:     {
 309:       System.arraycopy(obj,inOffset,pixelData,dataOffset,w);
 310:       dataOffset += scanlineStride;
 311:       inOffset += w;
 312:     }
 313:   }
 314:   
 315:   
 316:   public void setDataElements(int x, int y, Object obj, DataBuffer data)
 317:   {
 318:     int offset = scanlineStride*y + x + data.getOffset();
 319:     
 320:     int transferType = getTransferType();
 321:     if (getTransferType() != data.getDataType())
 322:       {
 323:     throw new IllegalArgumentException("transfer type ("+
 324:                        getTransferType()+"), "+
 325:                        "does not match data "+
 326:                        "buffer type (" +
 327:                        data.getDataType() +
 328:                        ").");
 329:       }
 330: 
 331:     try
 332:       {
 333:     switch (transferType)
 334:       {
 335:       case DataBuffer.TYPE_BYTE:
 336:         {
 337:           DataBufferByte out = (DataBufferByte) data;
 338:           byte[] in = (byte[]) obj;
 339:           out.getData()[offset] = in[0];
 340:           return;
 341:         }
 342:       case DataBuffer.TYPE_USHORT:
 343:         {
 344:           DataBufferUShort out = (DataBufferUShort) data;
 345:           short[] in = (short[]) obj;
 346:           out.getData()[offset] = in[0];
 347:           return;
 348:         }
 349:       case DataBuffer.TYPE_INT:
 350:         {
 351:           DataBufferInt out = (DataBufferInt) data;
 352:           int[] in = (int[]) obj;
 353:           out.getData()[offset] = in[0];
 354:           return;
 355:         }
 356:         // FIXME: Fill in the other possible types.
 357:       default:
 358:         throw new InternalError();
 359:       }
 360:       }
 361:     catch (ArrayIndexOutOfBoundsException aioobe)
 362:       {
 363:     String msg = "While writing data elements" +
 364:       ", x="+x+", y="+y+
 365:       ", width="+width+", height="+height+
 366:       ", scanlineStride="+scanlineStride+
 367:       ", offset="+offset+
 368:       ", data.getSize()="+data.getSize()+
 369:       ", data.getOffset()="+data.getOffset()+
 370:       ": " +
 371:       aioobe;
 372:     throw new ArrayIndexOutOfBoundsException(msg);
 373:       }
 374:     }
 375: 
 376:   public void setPixel(int x, int y, int[] iArray, DataBuffer data)
 377:   {
 378:     int offset = scanlineStride*y + x;
 379:     
 380:     int samples = 0;
 381:     for (int b=0; b<numBands; b++)
 382:       samples |= (iArray[b] << bitOffsets[b]) & bitMasks[b];
 383: 
 384:     data.setElem(offset, samples);
 385:   }
 386: 
 387:   /**
 388:    * This method implements a more efficient way to set pixels than the default
 389:    * implementation of the super class. It copies the pixel components directly
 390:    * from the input array instead of creating a intermediate buffer.
 391:    * @param x The x-coordinate of the pixel rectangle in <code>obj</code>.
 392:    * @param y The y-coordinate of the pixel rectangle in <code>obj</code>.
 393:    * @param w The width of the pixel rectangle in <code>obj</code>.
 394:    * @param h The height of the pixel rectangle in <code>obj</code>.
 395:    * @param iArray The primitive array containing the pixels to set.
 396:    * @param data The DataBuffer to store the pixels into.
 397:    * @see java.awt.image.SampleModel#setPixels(int, int, int, int, int[], java.awt.image.DataBuffer)
 398:    */
 399:   public void setPixels(int x, int y, int w, int h, int[] iArray,
 400:                         DataBuffer data)
 401:   {
 402:     int inOffset = 0;
 403:     int[] pixel = new int[numBands];
 404:     for (int yy=y; yy<(y+h); yy++)
 405:      {
 406:       int offset = scanlineStride*yy + x;
 407:       for (int xx=x; xx<(x+w); xx++)
 408:        { 
 409:         int samples = 0;
 410:         for (int b=0; b<numBands; b++)
 411:           samples |= (iArray[inOffset+b] << bitOffsets[b]) & bitMasks[b];
 412:         data.setElem(0, offset, samples);
 413:         inOffset += numBands;
 414:         offset += 1;
 415:       }
 416:     }
 417:   }
 418:   
 419:   
 420:   public void setSample(int x, int y, int b, int s, DataBuffer data)
 421:   {
 422:     int offset = scanlineStride*y + x;
 423:     int samples = data.getElem(offset);
 424:     int bitMask = bitMasks[b];
 425:     samples &= ~bitMask;
 426:     samples |= (s << bitOffsets[b]) & bitMask;
 427:     data.setElem(offset, samples);
 428:   }
 429:   
 430:   /**
 431:    * Creates a String with some information about this SampleModel.
 432:    * @return A String describing this SampleModel.
 433:    * @see java.lang.Object#toString()
 434:    */
 435:   public String toString()
 436:   {
 437:     StringBuffer result = new StringBuffer();
 438:     result.append(getClass().getName());
 439:     result.append("[");
 440:     result.append("scanlineStride=").append(scanlineStride);
 441:     for(int i=0; i < bitMasks.length; i+=1)
 442:     {
 443:       result.append(", mask[").append(i).append("]=0x").append(Integer.toHexString(bitMasks[i]));
 444:     }
 445:     
 446:     result.append("]");
 447:     return result.toString();
 448:   }
 449: }