Source for java.awt.image.BandedSampleModel

   1: /* Copyright (C) 2004, 2005, 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: /**
  40:  * MultiPixelPackedSampleModel provides a single band model that supports
  41:  * multiple pixels in a single unit.  Pixels have 2^n bits and 2^k pixels fit
  42:  * per data element.
  43:  *
  44:  * @author Jerry Quinn (jlquinn@optonline.net)
  45:  */
  46: public final class BandedSampleModel extends ComponentSampleModel
  47: {
  48:   private int[] bitMasks;
  49:   private int[] bitOffsets;
  50:   private int[] sampleSize;
  51:   private int dataBitOffset;
  52:   private int elemBits;
  53:   private int numberOfBits;
  54:   private int numElems;
  55: 
  56:   private static int[] createBankArray(int size) 
  57:   {
  58:     int[] result = new int[size];
  59:     for (int i = 0; i < size; i++)
  60:       result[i] = i;
  61:     return result;
  62:   }
  63: 
  64:   public BandedSampleModel(int dataType, int w, int h, int numBands)
  65:   {
  66:     this(dataType, w, h, w, createBankArray(numBands), new int[numBands]);
  67:   }
  68: 
  69:   public BandedSampleModel(int dataType, int w, int h, int scanlineStride,
  70:                int[] bankIndices, int[] bandOffsets)
  71:   {
  72:     super(dataType, w, h, 1, scanlineStride, bankIndices, bandOffsets);
  73:   }
  74: 
  75:   public SampleModel createCompatibleSampleModel(int w, int h)
  76:   {
  77:     // NOTE: blackdown 1.4.1 sets all offsets to 0.  Sun's 1.4.2 docs
  78:     // disagree.
  79: 
  80:     // Compress offsets so minimum is 0, others w*scanlineStride
  81:     int[] newoffsets = new int[bandOffsets.length];
  82:     int[] order = new int[bandOffsets.length];
  83:     for (int i=0; i < bandOffsets.length; i++)
  84:       order[i] = i;
  85:     // FIXME: This is N^2, but not a big issue, unless there's a lot of
  86:     // bands...
  87:     for (int i=0; i < bandOffsets.length; i++)
  88:       for (int j=i+1; j < bandOffsets.length; i++)
  89:     if (bankIndices[order[i]] > bankIndices[order[j]]
  90:         || (bankIndices[order[i]] == bankIndices[order[j]]
  91:         && bandOffsets[order[i]] > bandOffsets[order[j]]))
  92:       {
  93:         int t = order[i]; order[i] = order[j]; order[j] = t;
  94:       }
  95:     int bank = 0;
  96:     int offset = 0;
  97:     for (int i=0; i < bandOffsets.length; i++)
  98:       {
  99:     if (bankIndices[order[i]] != bank)
 100:       {
 101:         bank = bankIndices[order[i]];
 102:         offset = 0;
 103:       }
 104:     newoffsets[order[i]] = offset;
 105:     offset += w * scanlineStride;
 106:       }
 107:     
 108:     return new BandedSampleModel(dataType, w, h, scanlineStride, bankIndices, newoffsets);
 109:   }
 110: 
 111: 
 112:   public SampleModel createSubsetSampleModel(int[] bands)
 113:   {
 114:     if (bands.length > bankIndices.length)
 115:       throw new
 116:     RasterFormatException("BandedSampleModel createSubsetSampleModel too"
 117:                   +" many bands");
 118:     int[] newoff = new int[bands.length];
 119:     int[] newbanks = new int[bands.length];
 120:     for (int i=0; i < bands.length; i++)
 121:       {
 122:     int b = bands[i];
 123:     newoff[i] = bandOffsets[b];
 124:     newbanks[i] = bankIndices[b];
 125:       }
 126: 
 127:     return new BandedSampleModel(dataType, width, height, scanlineStride,
 128:                  newbanks, newoff);
 129:   }
 130: 
 131:   /**
 132:    * Extract all samples of one pixel and return in an array of transfer type.
 133:    *
 134:    * Extracts the pixel at x, y from data and stores samples into the array
 135:    * obj.  If obj is null, a new array of getTransferType() is created.
 136:    *
 137:    * @param x The x-coordinate of the pixel rectangle to store in <code>obj</code>.
 138:    * @param y The y-coordinate of the pixel rectangle to store in <code>obj</code>.
 139:    * @param obj The primitive array to store the pixels into or null to force creation.
 140:    * @param data The DataBuffer that is the source of the pixel data.
 141:    * @return The primitive array containing the pixel data.
 142:    * @see java.awt.image.SampleModel#getDataElements(int, int, java.lang.Object, java.awt.image.DataBuffer)
 143:    */
 144:   public Object getDataElements(int x, int y, Object obj,
 145:                 DataBuffer data)
 146:   {
 147:     int pixel = getSample(x, y, 0, data);
 148:     switch (getTransferType())
 149:     {
 150:     case DataBuffer.TYPE_BYTE:
 151:       {
 152:     byte[] b = (byte[])obj;
 153:     if (b == null) b = new byte[numBands];
 154:     for (int i=0; i < numBands; i++)
 155:       b[i] = (byte)getSample(x, y, i, data);
 156:     return b;
 157:       }
 158:     case DataBuffer.TYPE_SHORT:
 159:     case DataBuffer.TYPE_USHORT:
 160:       {
 161:     short[] b = (short[])obj;
 162:     if (b == null) b = new short[numBands];
 163:     for (int i=0; i < numBands; i++)
 164:       b[i] = (short)getSample(x, y, i, data);
 165:     return b;
 166:       }
 167:     case DataBuffer.TYPE_INT:
 168:       {
 169:     int[] b = (int[])obj;
 170:     if (b == null) b = new int[numBands];
 171:     for (int i=0; i < numBands; i++)
 172:       b[i] = getSample(x, y, i, data);
 173:     return b;
 174:       }
 175:     case DataBuffer.TYPE_FLOAT:
 176:       {
 177:     float[] b = (float[])obj;
 178:     if (b == null) b = new float[numBands];
 179:     for (int i=0; i < numBands; i++)
 180:       b[i] = getSampleFloat(x, y, i, data);
 181:     return b;
 182:       }
 183:     case DataBuffer.TYPE_DOUBLE:
 184:       {
 185:     double[] b = (double[])obj;
 186:     if (b == null) b = new double[numBands];
 187:     for (int i=0; i < numBands; i++)
 188:       b[i] = getSample(x, y, i, data);
 189:     return b;
 190:       }
 191: 
 192:     default:
 193:       // Seems like the only sensible thing to do.
 194:       throw new ClassCastException();
 195:     }
 196:   }
 197: 
 198:   public int[] getPixel(int x, int y, int[] iArray, DataBuffer data)
 199:   {
 200:     if (iArray == null) iArray = new int[numBands];
 201:     for (int i=0; i < numBands; i++)
 202:       iArray[i] = getSample(x, y, i, data);
 203:     
 204:     return iArray;
 205:   }
 206: 
 207:   /**
 208:    * Copy pixels from a region into an array.
 209:    *
 210:    * Copies the samples of the pixels in the rectangle starting at x, y that
 211:    * is w pixels wide and h scanlines high.  When there is more than one band,
 212:    * the samples stored in order before the next pixel.  This ordering isn't
 213:    * well specified in Sun's docs as of 1.4.2.
 214:    *
 215:    * If iArray is null, a new array is allocated, filled, and returned.
 216:    *
 217:    * @param x The x-coordinate of the pixel rectangle to store in
 218:    * <code>iArray</code>.
 219:    * @param y The y-coordinate of the pixel rectangle to store in
 220:    * <code>iArray</code>.
 221:    * @param w The width in pixels of the rectangle.
 222:    * @param h The height in pixels of the rectangle.
 223:    * @param iArray The int array to store the pixels into or null to force
 224:    * creation.
 225:    * @param data The DataBuffer that is the source of the pixel data.
 226:    * @return The primitive array containing the pixel data.
 227:    */
 228:   public int[] getPixels(int x, int y, int w, int h, int[] iArray,
 229:              DataBuffer data)
 230:   {
 231:     if (iArray == null) iArray = new int[w*h*numBands];
 232:     int outOffset = 0;
 233:     int maxX = x + w;
 234:     int maxY = y + h;
 235:     for (int yy = x; yy < maxY; yy++)
 236:       {
 237:     for (int xx = x; xx < maxX; xx++)
 238:       {
 239:         for (int b = 0; b < numBands; b++)
 240:           {
 241:         int offset = bandOffsets[b] + yy * scanlineStride + xx;
 242:         iArray[outOffset++] =
 243:           data.getElem(bankIndices[b], offset);
 244:           }
 245:       }
 246:       }
 247:     return iArray;    
 248:   }
 249: 
 250:   public int getSample(int x, int y, int b, DataBuffer data)
 251:   {
 252:     int offset = bandOffsets[b] + y * scanlineStride + x;
 253:     return data.getElem(bankIndices[b], offset);
 254:   }
 255:   
 256:   public float getSampleFloat(int x, int y, int b, DataBuffer data)
 257:   {
 258:     int offset = bandOffsets[b] + y * scanlineStride + x;
 259:     return data.getElemFloat(bankIndices[b], offset);
 260:   }
 261:   
 262:   public double getSampleDouble(int x, int y, int b, DataBuffer data)
 263:   {
 264:     int offset = bandOffsets[b] + y * scanlineStride + x;
 265:     return data.getElemDouble(bankIndices[b], offset);
 266:   }
 267:   
 268:   /**
 269:    * Copy one band's samples from a region into an array.
 270:    *
 271:    * Copies from one band the samples of the pixels in the rectangle starting
 272:    * at x, y that is w pixels wide and h scanlines high.
 273:    *
 274:    * If iArray is null, a new array is allocated, filled, and returned.
 275:    *
 276:    * @param x The x-coordinate of the pixel rectangle to store in
 277:    * <code>iArray</code>.
 278:    * @param y The y-coordinate of the pixel rectangle to store in
 279:    * <code>iArray</code>.
 280:    * @param w The width in pixels of the rectangle.
 281:    * @param h The height in pixels of the rectangle.
 282:    * @param b The band to retrieve.
 283:    * @param iArray The int array to store the pixels into or null to force
 284:    * creation.
 285:    * @param data The DataBuffer that is the source of the pixel data.
 286:    * @return The primitive array containing the pixel data.
 287:    */
 288:   public int[] getSamples(int x, int y, int w, int h, int b, int[] iArray,
 289:               DataBuffer data)
 290:   {
 291:     if (iArray == null) iArray = new int[w*h];
 292:     int outOffset = 0;
 293:     int maxX = x + w;
 294:     int maxY = y + h;
 295:     for (int yy = y; yy < maxY; yy++)
 296:       {
 297:     for (int xx = x; xx < maxX; xx++)
 298:       {
 299:         int offset = bandOffsets[b] + yy * scanlineStride + xx;
 300:         iArray[outOffset++] =
 301:           data.getElem(bankIndices[b], offset);
 302:       }
 303:       }
 304:     return iArray;    
 305:   }
 306: 
 307: 
 308:   /**
 309:    * Set the pixel at x, y to the value in the first element of the primitive
 310:    * array obj.
 311:    *
 312:    * @param x The x-coordinate of the data elements in <code>obj</code>.
 313:    * @param y The y-coordinate of the data elements in <code>obj</code>.
 314:    * @param obj The primitive array containing the data elements to set.
 315:    * @param data The DataBuffer to store the data elements into.
 316:    * @see java.awt.image.SampleModel#setDataElements(int, int, int, int, java.lang.Object, java.awt.image.DataBuffer)
 317:    */
 318:   public void setDataElements(int x, int y, Object obj, DataBuffer data)
 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:     int offset = y * scanlineStride + x;
 332:     
 333:     try
 334:       {
 335:     switch (transferType)
 336:       {
 337:       case DataBuffer.TYPE_BYTE:
 338:         {
 339:           DataBufferByte out = (DataBufferByte) data;
 340:           byte[] in = (byte[]) obj;
 341:           for (int i=0; i < numBands; i++)
 342:         out.getData(bankIndices[i])[offset + bandOffsets[i]] = in[i];
 343:           return;
 344:         }
 345:       case DataBuffer.TYPE_SHORT:
 346:         {
 347:           DataBufferShort out = (DataBufferShort) data;
 348:           short[] in = (short[]) obj;
 349:           for (int i=0; i < numBands; i++)
 350:         out.getData(bankIndices[i])[offset + bandOffsets[i]] = in[i];
 351:           return;
 352:         }
 353:       case DataBuffer.TYPE_USHORT:
 354:         {
 355:           DataBufferUShort out = (DataBufferUShort) data;
 356:           short[] in = (short[]) obj;
 357:           for (int i=0; i < numBands; i++)
 358:         out.getData(bankIndices[i])[offset + bandOffsets[i]] = in[i];
 359:           return;
 360:         }
 361:       case DataBuffer.TYPE_INT:
 362:         {
 363:           DataBufferInt out = (DataBufferInt) data;
 364:           int[] in = (int[]) obj;
 365:           for (int i=0; i < numBands; i++)
 366:         out.getData(bankIndices[i])[offset + bandOffsets[i]] = in[i];
 367:           return;
 368:         }
 369:       case DataBuffer.TYPE_FLOAT:
 370:         {
 371:           DataBufferFloat out = (DataBufferFloat) data;
 372:           float[] in = (float[]) obj;
 373:           for (int i=0; i < numBands; i++)
 374:         out.getData(bankIndices[i])[offset + bandOffsets[i]] = in[i];
 375:           return;
 376:         }
 377:       case DataBuffer.TYPE_DOUBLE:
 378:         {
 379:           DataBufferDouble out = (DataBufferDouble) data;
 380:           double[] in = (double[]) obj;
 381:           for (int i=0; i < numBands; i++)
 382:         out.getData(bankIndices[i])[offset + bandOffsets[i]] = in[i];
 383:           return;
 384:         }
 385:       default:
 386:         throw new ClassCastException("Unsupported data type");
 387:       }
 388:       }
 389:     catch (ArrayIndexOutOfBoundsException aioobe)
 390:       {
 391:     String msg = "While writing data elements" +
 392:       ", x="+x+", y="+y+
 393:       ", width="+width+", height="+height+
 394:       ", scanlineStride="+scanlineStride+
 395:       ", offset="+offset+
 396:       ", data.getSize()="+data.getSize()+
 397:       ", data.getOffset()="+data.getOffset()+
 398:       ": " +
 399:       aioobe;
 400:     throw new ArrayIndexOutOfBoundsException(msg);
 401:       }
 402:     }
 403: 
 404:   public void setPixel(int x, int y, int[] iArray, DataBuffer data)
 405:   {
 406:     for (int b=0; b < numBands; b++)
 407:       data.setElem(bankIndices[b], bandOffsets[b] + y * scanlineStride + x,
 408:            iArray[b]);
 409:   }
 410: 
 411:   public void setPixels(int x, int y, int w, int h, int[] iArray,
 412:             DataBuffer data)
 413:   {
 414:     int inOffset = 0;
 415:     for (int hh = 0; hh < h; hh++)
 416:       {
 417:     for (int ww = 0; ww < w; ww++)
 418:       {
 419:         int offset = y * scanlineStride + (x + ww);
 420:         for (int b=0; b < numBands; b++)
 421:           data.setElem(bankIndices[b], bandOffsets[b] + offset,
 422:                iArray[inOffset++]);
 423:       }
 424:     y++;
 425:       }
 426:   }
 427: 
 428:   public void setSample(int x, int y, int b, int s, DataBuffer data)
 429:   {
 430:     data.setElem(bankIndices[b], bandOffsets[b] + y * scanlineStride + x, s);
 431:   }
 432:   
 433:   public void setSample(int x, int y, int b, float s, DataBuffer data)
 434:   {
 435:     data.setElemFloat(bankIndices[b], bandOffsets[b] + y * scanlineStride + x, s);
 436:   }
 437:   
 438:   public void setSample(int x, int y, int b, double s, DataBuffer data)
 439:   {
 440:     data.setElemDouble(bankIndices[b], bandOffsets[b] + y * scanlineStride + x, s);
 441:   }
 442:   
 443:   public void setSamples(int x, int y, int w, int h, int b, int[] iArray,
 444:              DataBuffer data)
 445:   {
 446:     int inOffset = 0;
 447: 
 448:     switch (getTransferType())
 449:       {
 450:       case DataBuffer.TYPE_BYTE:
 451:     {
 452:       DataBufferByte out = (DataBufferByte) data;
 453:       byte[] bank = out.getData(bankIndices[b]);
 454:       for (int hh = 0; hh < h; hh++)
 455:         {
 456:           for (int ww = 0; ww < w; ww++)
 457:         {
 458:           int offset = bandOffsets[b] + y * scanlineStride + (x + ww);
 459:           bank[offset] = (byte)iArray[inOffset++];
 460:         }
 461:           y++;
 462:         }
 463:       return;
 464:     }
 465:       case DataBuffer.TYPE_SHORT:
 466:     {
 467:       DataBufferShort out = (DataBufferShort) data;
 468:       short[] bank = out.getData(bankIndices[b]);
 469:       for (int hh = 0; hh < h; hh++)
 470:         {
 471:           for (int ww = 0; ww < w; ww++)
 472:         {
 473:           int offset = bandOffsets[b] + y * scanlineStride + (x + ww);
 474:           bank[offset] = (short)iArray[inOffset++];
 475:         }
 476:           y++;
 477:         }
 478:       return;
 479:     }
 480:       case DataBuffer.TYPE_USHORT:
 481:     {
 482:       DataBufferShort out = (DataBufferShort) data;
 483:       short[] bank = out.getData(bankIndices[b]);
 484:       for (int hh = 0; hh < h; hh++)
 485:         {
 486:           for (int ww = 0; ww < w; ww++)
 487:         {
 488:           int offset = bandOffsets[b] + y * scanlineStride + (x + ww);
 489:           bank[offset] = (short)iArray[inOffset++];
 490:         }
 491:           y++;
 492:         }
 493:       return;
 494:     }
 495:       case DataBuffer.TYPE_INT:
 496:     {
 497:       DataBufferInt out = (DataBufferInt) data;
 498:       int[] bank = out.getData(bankIndices[b]);
 499:       for (int hh = 0; hh < h; hh++)
 500:         {
 501:           for (int ww = 0; ww < w; ww++)
 502:         {
 503:           int offset = bandOffsets[b] + y * scanlineStride + (x + ww);
 504:           bank[offset] = iArray[inOffset++];
 505:         }
 506:           y++;
 507:         }
 508:       return;
 509:     }
 510:       case DataBuffer.TYPE_FLOAT:
 511:       case DataBuffer.TYPE_DOUBLE:
 512:     break;
 513:       default:
 514:     throw new ClassCastException("Unsupported data type");
 515:       }
 516: 
 517:     // Default implementation probably slower for float and double
 518:     for (int hh = 0; hh < h; hh++)
 519:       {
 520:     for (int ww = 0; ww < w; ww++)
 521:       {
 522:         int offset = bandOffsets[b] + y * scanlineStride + (x + ww);
 523:         data.setElem(bankIndices[b], offset, iArray[inOffset++]);
 524:       }
 525:     y++;
 526:       }
 527:   }
 528: 
 529:   /**
 530:    * Creates a String with some information about this SampleModel.
 531:    * @return A String describing this SampleModel.
 532:    * @see java.lang.Object#toString()
 533:    */
 534:   public String toString()
 535:   {
 536:     StringBuffer result = new StringBuffer();
 537:     result.append(getClass().getName());
 538:     result.append("[");
 539:     result.append("scanlineStride=").append(scanlineStride);
 540:     for(int i=0; i < bitMasks.length; i+=1)
 541:     {
 542:       result.append(", mask[").append(i).append("]=0x").append(Integer.toHexString(bitMasks[i]));
 543:     }
 544:     
 545:     result.append("]");
 546:     return result.toString();
 547:   }
 548: }