Source for java.awt.image.ComponentSampleModel

   1: /* Copyright (C) 2000, 2002  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.Buffers;
  40: 
  41: /* FIXME: This class does not yet support data type TYPE_SHORT */
  42: 
  43: /**
  44:  * ComponentSampleModel supports a flexible organization of pixel samples in
  45:  * memory, permitting pixel samples to be interleaved by band, by scanline,
  46:  * and by pixel.
  47:  *
  48:  * A DataBuffer for this sample model has K banks of data.  Pixels have N
  49:  * samples, so there are N bands in the DataBuffer.  Each band is completely
  50:  * contained in one bank of data, but a bank may contain more than one band.
  51:  * Each pixel sample is stored in a single data element.
  52:  *
  53:  * Within a bank, each band begins at an offset stored in bandOffsets.  The
  54:  * banks containing the band is given by bankIndices.  Within the bank, there
  55:  * are three dimensions - band, pixel, and scanline.  The dimension ordering
  56:  * is controlled by bandOffset, pixelStride, and scanlineStride, which means
  57:  * that any combination of interleavings is supported.
  58:  *
  59:  * @author Rolf W. Rasmussen (rolfwr@ii.uib.no)
  60:  */
  61: public class ComponentSampleModel extends SampleModel
  62: {
  63:   protected int[] bandOffsets;
  64:   protected int[] bankIndices;
  65:   
  66:   // FIXME: Should we really shadow the numBands in the superclass?
  67:   //protected int numBands;
  68:   
  69:   /** Used when creating data buffers. */
  70:   protected int numBanks;
  71: 
  72:   protected int scanlineStride;
  73:   
  74:   protected int pixelStride;
  75:   
  76:   private boolean tightPixelPacking = false;
  77:   
  78:   public ComponentSampleModel(int dataType,
  79:                   int w, int h,
  80:                   int pixelStride,
  81:                   int scanlineStride,
  82:                   int[] bandOffsets)
  83:   {
  84:     this(dataType, w, h, pixelStride, scanlineStride,
  85:      new int[bandOffsets.length], bandOffsets);
  86:   }
  87:     
  88:   public ComponentSampleModel(int dataType,
  89:                   int w, int h,
  90:                   int pixelStride,
  91:                   int scanlineStride,
  92:                   int[] bankIndices,
  93:                   int[] bandOffsets)
  94:   {
  95:     super(dataType, w, h, bandOffsets.length);
  96:     if ((pixelStride<0) || (scanlineStride<0) || 
  97:     (bandOffsets.length<1) ||
  98:     (bandOffsets.length != bankIndices.length))
  99:       throw new IllegalArgumentException();
 100:     
 101:     this.bandOffsets = bandOffsets;
 102:     this.bankIndices = bankIndices;
 103: 
 104:     this.numBanks = 0;
 105:     for (int b=0; b<bankIndices.length; b++)
 106:       this.numBanks = Math.max(this.numBanks, bankIndices[b]+1);
 107: 
 108:     this.scanlineStride = scanlineStride;
 109:     this.pixelStride = pixelStride;
 110: 
 111:     // See if we can use some speedups
 112: 
 113:     /* FIXME: May these checks should be reserved for the
 114:        PixelInterleavedSampleModel? */
 115:     
 116:     if (pixelStride == numBands)
 117:       {
 118:     tightPixelPacking = true;
 119:     for (int b=0; b<numBands; b++) {
 120:       if ((bandOffsets[b] != b) || (bankIndices[b] !=0))
 121:         {
 122:           tightPixelPacking = false;
 123:           break;
 124:         }
 125:     }
 126:       }
 127:   }        
 128: 
 129:   public SampleModel createCompatibleSampleModel(int w, int h)
 130:   {
 131:     return new ComponentSampleModel(dataType, w, h, pixelStride,
 132:                     scanlineStride, bankIndices,
 133:                     bandOffsets);
 134:   }
 135: 
 136:   public SampleModel createSubsetSampleModel(int[] bands)
 137:   {
 138:     int numBands = bands.length;
 139:     
 140:     int[] bankIndices = new int[numBands];
 141:     int[] bandOffsets = new int[numBands];
 142:     for (int b=0; b<numBands; b++)
 143:       {
 144:     bankIndices[b] = this.bankIndices[bands[b]];
 145:     bandOffsets[b] = this.bandOffsets[bands[b]];
 146:       }
 147: 
 148:     return new ComponentSampleModel(dataType, width, height, pixelStride,
 149:                     scanlineStride, bankIndices,
 150:                     bandOffsets);
 151:   }
 152: 
 153:   public DataBuffer createDataBuffer()
 154:   {
 155:     // Maybe this value should be precalculated in the constructor?
 156:     int highestOffset = 0;
 157:     for (int b=0; b<numBands; b++)
 158:       {
 159:     highestOffset = Math.max(highestOffset, bandOffsets[b]);
 160:       }
 161:     int size = pixelStride*(width-1) + scanlineStride*(height-1) +
 162:       highestOffset + 1;
 163:     
 164:     return Buffers.createBuffer(getDataType(), size, numBanks);
 165:   }
 166: 
 167:   public int getOffset(int x, int y)
 168:   {
 169:     return getOffset(x, y, 0);
 170:   }
 171: 
 172:   public int getOffset(int x, int y, int b)
 173:   {
 174:     return bandOffsets[b] + pixelStride*x + scanlineStride*y;
 175:   }
 176: 
 177:   public final int[] getSampleSize()
 178:   {
 179:     int size = DataBuffer.getDataTypeSize(getDataType());
 180:     int[] sizes = new int[numBands];
 181: 
 182:     java.util.Arrays.fill(sizes, size);
 183:     return sizes;
 184:   }
 185: 
 186:   public final int getSampleSize(int band)
 187:   {
 188:     return DataBuffer.getDataTypeSize(getDataType());
 189:   }
 190: 
 191:   public final int[] getBankIndices()
 192:   {
 193:     return bankIndices;
 194:   }
 195: 
 196:   public final int[] getBandOffsets()
 197:   {
 198:     return bandOffsets;
 199:   }
 200: 
 201:   public final int getScanlineStride()
 202:   {
 203:     return scanlineStride;
 204:   }
 205: 
 206:   public final int getPixelStride()
 207:   {
 208:     return pixelStride;
 209:   }
 210: 
 211:   public final int getNumDataElements()
 212:   {
 213:     return numBands;
 214:   }
 215: 
 216:   public Object getDataElements(int x, int y, Object obj, DataBuffer data)
 217:   {
 218:     int xyOffset = pixelStride*x + scanlineStride*y;
 219:     
 220:     int[] totalBandDataOffsets = new int[numBands];
 221:     
 222:     /* Notice that band and bank offsets are different. Band offsets
 223:        are managed by the sample model, and bank offsets are managed
 224:        by the data buffer. Both must be accounted for. */
 225:     
 226:     /* FIXME: For single pixels, it is probably easier to simple
 227:        call getElem instead of calculating the bank offset ourself.
 228:        
 229:        On the other hand, then we need to push the value through
 230:        the int type returned by the getElem method.  */
 231:     
 232:     int[] bankOffsets = data.getOffsets();
 233:     
 234:     for (int b=0; b<numBands; b++)
 235:       {
 236:     totalBandDataOffsets[b] = 
 237:       bandOffsets[b]+bankOffsets[bankIndices[b]] + xyOffset;
 238:       }
 239:     
 240:     try
 241:       {
 242:     switch (getTransferType())
 243:       {
 244:       case DataBuffer.TYPE_BYTE:
 245:         DataBufferByte inByte = (DataBufferByte) data;
 246:         byte[] outByte = (byte[]) obj;
 247:         if (outByte == null) outByte = new byte[numBands];
 248:         
 249:         for (int b=0; b<numBands; b++)
 250:           {
 251:         int dOffset = totalBandDataOffsets[b];
 252:         outByte[b] = inByte.getData(bankIndices[b])[dOffset];
 253:           }
 254:         return outByte;
 255:         
 256:       case DataBuffer.TYPE_USHORT:
 257:         DataBufferUShort inUShort = (DataBufferUShort) data;
 258:         short[] outUShort = (short[]) obj;
 259:         if (outUShort == null) outUShort = new short[numBands];
 260:         
 261:         for (int b=0; b<numBands; b++)
 262:           {
 263:         int dOffset = totalBandDataOffsets[b];
 264:         outUShort[b] = inUShort.getData(bankIndices[b])[dOffset];
 265:           }
 266:         return outUShort;
 267: 
 268:       case DataBuffer.TYPE_SHORT:
 269:         DataBufferShort inShort = (DataBufferShort) data;
 270:         short[] outShort = (short[]) obj;
 271:         if (outShort == null) outShort = new short[numBands];
 272:         
 273:         for (int b=0; b<numBands; b++)
 274:           {
 275:         int dOffset = totalBandDataOffsets[b];
 276:         outShort[b] = inShort.getData(bankIndices[b])[dOffset];
 277:           }
 278:         return outShort;
 279: 
 280:       case DataBuffer.TYPE_INT:
 281:         DataBufferInt inInt = (DataBufferInt) data;
 282:         int[] outInt = (int[]) obj;
 283:         if (outInt == null) outInt = new int[numBands];
 284:         
 285:         for (int b=0; b<numBands; b++)
 286:           {
 287:         int dOffset = totalBandDataOffsets[b];
 288:         outInt[b] = inInt.getData(bankIndices[b])[dOffset];
 289:           }
 290:         return outInt;
 291: 
 292:       case DataBuffer.TYPE_FLOAT:
 293:         DataBufferFloat inFloat = (DataBufferFloat) data;
 294:         float[] outFloat = (float[]) obj;
 295:         if (outFloat == null) outFloat = new float[numBands];
 296: 
 297:         for (int b=0; b<numBands; b++)
 298:           {
 299:         int dOffset = totalBandDataOffsets[b];
 300:         outFloat[b] = inFloat.getData(bankIndices[b])[dOffset];
 301:           }
 302:         return outFloat;
 303:         
 304:       case DataBuffer.TYPE_DOUBLE:
 305:         DataBufferDouble inDouble = (DataBufferDouble) data;
 306:         double[] outDouble = (double[]) obj;
 307:         if (outDouble == null) outDouble = new double[numBands];
 308: 
 309:         for (int b=0; b<numBands; b++)
 310:           {
 311:         int dOffset = totalBandDataOffsets[b];
 312:         outDouble[b] = inDouble.getData(bankIndices[b])[dOffset];
 313:           }
 314:         return outDouble;
 315:         
 316:       default:
 317:           throw new IllegalStateException("unknown transfer type " +
 318:                           getTransferType());
 319:       }
 320:       }
 321:     catch (ArrayIndexOutOfBoundsException aioobe)
 322:       {
 323:     String msg = "While reading data elements, " +
 324:       "x=" + x + ", y=" + y +", " + ", xyOffset=" + xyOffset +
 325:       ", data.getSize()=" + data.getSize() + ": " + aioobe;
 326:     throw new ArrayIndexOutOfBoundsException(msg);
 327:       }
 328:   }
 329: 
 330:   public Object getDataElements(int x, int y, int w, int h, Object obj,
 331:                 DataBuffer data)
 332:   {
 333:     if (!tightPixelPacking)
 334:       {
 335:     return super.getDataElements(x, y, w, h, obj, data);
 336:       }
 337: 
 338:     // using get speedup
 339:     
 340:     // We can copy whole rows
 341:     int rowSize = w*numBands;
 342:     int dataSize = rowSize*h;
 343:     
 344:     DataBuffer transferBuffer =
 345:       Buffers.createBuffer(getTransferType(), obj, dataSize);
 346:     obj = Buffers.getData(transferBuffer);
 347: 
 348:     int inOffset =
 349:       pixelStride*x +
 350:       scanlineStride*y +
 351:       data.getOffset(); // Assumes only one band is used
 352: 
 353:     /* We don't add band offsets since we assume that bands have
 354:        offsets 0, 1, 2, ... */
 355: 
 356:     // See if we can copy everything in one go
 357:     if (scanlineStride == rowSize)
 358:       {
 359:     // Collapse scan lines:
 360:     rowSize *= h;
 361:     // We ignore scanlineStride since it won't be of any use
 362:     h = 1;
 363:       }
 364: 
 365:     int outOffset = 0;
 366:     Object inArray = Buffers.getData(data);
 367:     for (int yd = 0; yd<h; yd++)
 368:       {
 369:     System.arraycopy(inArray, inOffset, obj, outOffset, rowSize);
 370:     inOffset  += scanlineStride;
 371:     outOffset += rowSize;
 372:       }
 373:     return obj;
 374:   }
 375: 
 376:   public void setDataElements(int x, int y, int w, int h,
 377:                   Object obj, DataBuffer data)
 378:   {
 379:     if (!tightPixelPacking)
 380:       {
 381:     super.setDataElements(x, y, w, h, obj, data);
 382:     return;
 383:       }
 384: 
 385:     // using set speedup, we can copy whole rows
 386:     int rowSize = w*numBands;
 387:     int dataSize = rowSize*h;
 388:     
 389:     DataBuffer transferBuffer =
 390:       Buffers.createBufferFromData(getTransferType(), obj, dataSize);
 391: 
 392:     int[] bankOffsets = data.getOffsets();
 393: 
 394:     int outOffset =
 395:       pixelStride*x +
 396:       scanlineStride*y +
 397:       bankOffsets[0]; // same assuptions as in get...
 398: 
 399:     // See if we can copy everything in one go
 400:     if (scanlineStride == rowSize)
 401:       {
 402:     // Collapse scan lines:
 403:     rowSize *= h;
 404:     h = 1;
 405:       }
 406: 
 407:     int inOffset = 0;
 408:     Object outArray = Buffers.getData(data);
 409:     for (int yd = 0; yd<h; yd++)
 410:       {
 411:     System.arraycopy(obj, inOffset, outArray, outOffset, rowSize);
 412:     outOffset += scanlineStride;
 413:     inOffset  += rowSize;
 414:       }
 415:   }
 416: 
 417:   public int[] getPixel(int x, int y, int[] iArray, DataBuffer data)
 418:   {
 419:     int offset = pixelStride*x + scanlineStride*y;
 420:     if (iArray == null) iArray = new int[numBands];
 421:     for (int b=0; b<numBands; b++)
 422:       {
 423:     iArray[b] = data.getElem(bankIndices[b], offset+bandOffsets[b]);
 424:       }
 425:     return iArray;
 426:   }
 427: 
 428:   public int[] getPixels(int x, int y, int w, int h, int[] iArray,
 429:              DataBuffer data)
 430:   {
 431:     int offset = pixelStride*x + scanlineStride*y;
 432:     if (iArray == null) iArray = new int[numBands*w*h];
 433:     int outOffset = 0;
 434:     for (y=0; y<h; y++)
 435:       {
 436:     int lineOffset = offset;
 437:     for (x=0; x<w; x++)
 438:       {
 439:         for (int b=0; b<numBands; b++)
 440:           {
 441:         iArray[outOffset++] = 
 442:           data.getElem(bankIndices[b], lineOffset+bandOffsets[b]);
 443:           }
 444:         lineOffset += pixelStride;
 445:       }
 446:     offset += scanlineStride;
 447:       }
 448:     return iArray;
 449:   }
 450:     
 451:   public int getSample(int x, int y, int b, DataBuffer data)
 452:   {
 453:     return data.getElem(bankIndices[b], getOffset(x, y, b));
 454:   }
 455: 
 456:   public void setDataElements(int x, int y, Object obj, DataBuffer data)
 457:   {
 458:     int offset = pixelStride*x + scanlineStride*y;
 459:     int[] totalBandDataOffsets = new int[numBands];
 460:     int[] bankOffsets = data.getOffsets();
 461:     for (int b=0; b<numBands; b++)
 462:       totalBandDataOffsets[b] =
 463:     bandOffsets[b]+bankOffsets[bankIndices[b]] + offset;
 464: 
 465:     switch (getTransferType())
 466:       {
 467:       case DataBuffer.TYPE_BYTE:
 468:     {
 469:       DataBufferByte out = (DataBufferByte) data;
 470:       byte[] in = (byte[]) obj;
 471:       
 472:       for (int b=0; b<numBands; b++)
 473:         out.getData(bankIndices[b])[totalBandDataOffsets[b]] = in[b];
 474:       
 475:       return;
 476:     }
 477:       case DataBuffer.TYPE_USHORT:
 478:     {
 479:       DataBufferUShort out = (DataBufferUShort) data;
 480:       short[] in = (short[]) obj;
 481:       
 482:       for (int b=0; b<numBands; b++)
 483:         out.getData(bankIndices[b])[totalBandDataOffsets[b]] = in[b];
 484:       
 485:       return;
 486:     }
 487:       case DataBuffer.TYPE_SHORT:
 488:     {
 489:       DataBufferShort out = (DataBufferShort) data;
 490:       short[] in = (short[]) obj;
 491:       
 492:       for (int b=0; b<numBands; b++)
 493:         out.getData(bankIndices[b])[totalBandDataOffsets[b]] = in[b];
 494:       
 495:       return;
 496:     }
 497:       case DataBuffer.TYPE_INT:
 498:     {
 499:       DataBufferInt out = (DataBufferInt) data;
 500:       int[] in = (int[]) obj;
 501:       
 502:       for (int b=0; b<numBands; b++)
 503:         out.getData(bankIndices[b])[totalBandDataOffsets[b]] = in[b];
 504:       
 505:       return;
 506:     }
 507:       case DataBuffer.TYPE_FLOAT:
 508:     {
 509:       DataBufferFloat out = (DataBufferFloat) data;
 510:       float[] in = (float[]) obj;
 511:       
 512:       for (int b=0; b<numBands; b++)
 513:         out.getData(bankIndices[b])[totalBandDataOffsets[b]] = in[b];
 514:       
 515:       return;
 516:     }
 517:       case DataBuffer.TYPE_DOUBLE:
 518:     {
 519:       DataBufferDouble out = (DataBufferDouble) data;
 520:       double[] in = (double[]) obj;
 521:       
 522:       for (int b=0; b<numBands; b++)
 523:         out.getData(bankIndices[b])[totalBandDataOffsets[b]] = in[b];
 524:       
 525:       return;
 526:     }
 527:       default:
 528:     throw new UnsupportedOperationException("transfer type not " +
 529:                         "implemented");
 530:       }
 531:   }
 532:   
 533:   public void setPixel(int x, int y, int[] iArray, DataBuffer data)
 534:   {
 535:     int offset = pixelStride*x + scanlineStride*y;
 536:     for (int b=0; b<numBands; b++)
 537:       data.setElem(bankIndices[b], offset+bandOffsets[b], iArray[b]);
 538:   }
 539:     
 540:   public void setSample(int x, int y, int b, int s, DataBuffer data)
 541:   {
 542:     data.setElem(bankIndices[b], getOffset(x, y, b), s);
 543:   }
 544: }