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