Changeset 1806


Ignore:
Timestamp:
11/17/06 09:06:14 (13 years ago)
Author:
melissa
Message:
  • Added command-line option to normalize floating point data.
  • Expanded ImageTools logic to do better autoscaling.
  • Fixed bugs and type mismatches in various readers.
  • Fixed bug in how FileStitcher handles files with different numbers of images.
  • Added support for MRC file format (similar to Deltavision).
  • Removed end-of-line spaces.
Location:
trunk/loci/formats
Files:
1 added
33 edited

Legend:

Unmodified
Added
Removed
  • trunk/loci/formats/ChannelMerger.java

    r1718 r1806  
    4444  public boolean canMerge(String id) throws FormatException, IOException { 
    4545    int c = getSizeC(id); 
    46     return c > 1 && !(c >= 3 && reader.isRGB(id)); 
     46    return c > 1 && c <= 4 && !(c >= 3 && reader.isRGB(id)); 
    4747  } 
    4848 
  • trunk/loci/formats/ChannelSeparator.java

    r1718 r1806  
    8989    }; 
    9090 
    91     return ImageTools.makeImage(openBytes(id, no), getSizeX(id), getSizeY(id), 
    92       1, false, bytes, isLittleEndian(id)); 
     91    byte[] b = openBytes(id, no); 
     92 
     93    if (getPixelType(id) == FormatReader.FLOAT) { 
     94      float[] f = new float[b.length / 4]; 
     95      for (int i=0; i<b.length; i+=4) { 
     96        f[i/4] = Float.intBitsToFloat(DataTools.bytesToInt(b, i, 4, 
     97          isLittleEndian(id))); 
     98      } 
     99      if (getNormalize()) f = DataTools.normalizeFloats(f); 
     100      return ImageTools.makeImage(f, getSizeX(id), getSizeY(id)); 
     101    } 
     102 
     103    return ImageTools.makeImage(b, getSizeX(id), getSizeY(id), 1, false, 
     104      bytes, isLittleEndian(id)); 
    93105  } 
    94106 
  • trunk/loci/formats/DataTools.java

    r1777 r1806  
    200200    byte[] rtn = new byte[8]; 
    201201    long l = Double.doubleToLongBits(v); 
    202      
     202 
    203203    if (little) { 
    204204      rtn[0] = (byte) (l & 0xff); 
     
    222222    } 
    223223    return rtn; 
    224   }  
     224  } 
    225225 
    226226 
     
    488488  } 
    489489 
     490  /** 
     491   * Convert a byte array to the appropriate primitive type array. 
     492   * The 'bpp' parameter denotes the number of bytes in the returned primitive 
     493   * type (e.g. if bpp == 2, we should return an array of type short). 
     494   * If 'fp' is set and bpp == 4 or bpp == 8, then return floats or doubles. 
     495   */ 
     496  public static Object makeDataArray(byte[] b, int bpp, boolean fp, 
     497    boolean little) 
     498  { 
     499    if (bpp == 1) return b; 
     500    else if (bpp == 2) { 
     501      short[] s = new short[b.length / 2]; 
     502      for (int i=0; i<s.length; i++) { 
     503        s[i] = bytesToShort(b, i*2, 2, little); 
     504      } 
     505      return s; 
     506    } 
     507    else if (bpp == 4 && fp) { 
     508      float[] f = new float[b.length / 4]; 
     509      for (int i=0; i<f.length; i++) { 
     510        f[i] = Float.intBitsToFloat(bytesToInt(b, i*4, 4, little)); 
     511      } 
     512      return f; 
     513    } 
     514    else if (bpp == 4) { 
     515      int[] i = new int[b.length / 4]; 
     516      for (int j=0; j<i.length; j++) { 
     517        i[j] = bytesToInt(b, j*4, 4, little); 
     518      } 
     519      return i; 
     520    } 
     521    else if (bpp == 8 && fp) { 
     522      double[] d = new double[b.length / 8]; 
     523      for (int i=0; i<d.length; i++) { 
     524        d[i] = Double.longBitsToDouble(bytesToLong(b, i*8, 8, little)); 
     525      } 
     526      return d; 
     527    } 
     528    else if (bpp == 8) { 
     529      long[] l = new long[b.length / 8]; 
     530      for (int i=0; i<l.length; i++) { 
     531        l[i] = bytesToLong(b, i*8, 8, little); 
     532      } 
     533      return l; 
     534    } 
     535    return null; 
     536  } 
     537 
     538  /** 
     539   * Normalize the given float array so that the minimum value maps to 0.0 
     540   * and the maximum value maps to 1.0. 
     541   */ 
     542  public static float[] normalizeFloats(float[] data) { 
     543    float[] rtn = new float[data.length]; 
     544 
     545    // make a quick pass through to determine the real min and max values 
     546 
     547    float min = Float.MAX_VALUE; 
     548    float max = Float.MIN_VALUE; 
     549    int maxNdx = 0; 
     550 
     551    for (int i=0; i<data.length; i++) { 
     552      if (data[i] < min) min = data[i]; 
     553      if (data[i] > max) { 
     554        max = data[i]; 
     555        maxNdx = i; 
     556      } 
     557    } 
     558 
     559    // now normalize; min => 0.0, max => 1.0 
     560 
     561    for (int i=0; i<rtn.length; i++) { 
     562      rtn[i] = data[i] / max; 
     563      if (rtn[i] < 0f) rtn[i] = 0f; 
     564      if (rtn[i] > 1f) rtn[i] = 1f; 
     565    } 
     566 
     567    return rtn; 
     568  } 
     569 
    490570} 
  • trunk/loci/formats/FilePattern.java

    r1805 r1806  
    308308    String[] nameList = new String[f.length]; 
    309309    for (int i=0; i<nameList.length; i++) nameList[i] = f[i].getName(); 
    310   
     310 
    311311    return findPattern(name, dir, nameList); 
    312312  } 
  • trunk/loci/formats/FileStitcher.java

    r1804 r1806  
    9191  /** Whether or not to ignore color tables, if present. */ 
    9292  protected boolean ignoreColorTable = false; 
     93 
     94  /** Whether or not to normalize float data. */ 
     95  protected boolean normalizeData = false; 
    9396 
    9497  // -- Constructors -- 
     
    310313    int[] q = computeIndices(id, no); 
    311314    int fno = q[0], ino = q[1]; 
    312     return readers[fno].openImage(files[fno], ino); 
     315    if (ino < readers[fno].getImageCount(files[fno])) { 
     316      return readers[fno].openImage(files[fno], ino); 
     317    } 
     318    // inserting a blank image may not be the best way to handle files with 
     319    // different image counts, but we need to do something 
     320    return ImageTools.blankImage(width, height, 
     321      readers[fno].getSizeC(files[fno]), readers[fno].getPixelType(files[fno])); 
    313322 
    314323    //CTR TODO - come up with an API for Chris, for setting the axes for the 
     
    325334    int[] q = computeIndices(id, no); 
    326335    int fno = q[0], ino = q[1]; 
    327     return readers[fno].openBytes(files[fno], ino); 
     336    if (ino < readers[fno].getImageCount(files[fno])) { 
     337      return readers[fno].openBytes(files[fno], ino); 
     338    } 
     339 
     340    int bytes = 0; 
     341    switch (readers[fno].getPixelType(files[fno])) { 
     342      case FormatReader.INT8: 
     343      case FormatReader.UINT8: bytes = 1; break; 
     344      case FormatReader.INT16: 
     345      case FormatReader.UINT16: bytes = 2; break; 
     346      case FormatReader.INT32: 
     347      case FormatReader.UINT32: 
     348      case FormatReader.FLOAT: bytes = 4; break; 
     349      case FormatReader.DOUBLE: bytes = 8; break; 
     350    } 
     351    return new byte[width * height * bytes * readers[fno].getSizeC(files[fno])]; 
    328352  } 
    329353 
     
    386410    ignoreColorTable = ignore; 
    387411  } 
     412 
     413  /* @see IFormatReader#setNormalize(boolean) */ 
     414  public void setNormalize(boolean normalize) { 
     415    normalizeData = normalize; 
     416  } 
     417 
     418  /* @see IFormatReader#getNormalize() */ 
     419  public boolean getNormalize() { return normalizeData; } 
    388420 
    389421  /* @see IFormatReader#swapDimensions(String, String) */ 
  • trunk/loci/formats/FormatReader.java

    r1783 r1806  
    2626 
    2727import java.awt.image.BufferedImage; 
     28//import java.awt.image.DataBuffer; 
    2829import java.io.*; 
    2930import java.lang.reflect.Method; 
     
    105106  protected boolean ignoreColorTable = false; 
    106107 
     108  /** Whether or not to normalize float data. */ 
     109  protected boolean normalizeData; 
     110 
    107111  /** 
    108112   * Current metadata store. Should <b>never</b> be accessed directly as the 
     
    339343    ignoreColorTable = ignore; 
    340344  } 
     345 
     346  /** Specify whether or not to normalize float data. */ 
     347  public void setNormalize(boolean normalize) { 
     348    normalizeData = normalize; 
     349  } 
     350 
     351  /** Return true if we should normalize float data. */ 
     352  public boolean getNormalize() { return normalizeData; } 
    341353 
    342354  /** 
     
    493505    boolean omexml = false; 
    494506    boolean ignoreColors = false; 
     507    boolean normalize = false; 
    495508    int start = 0; 
    496509    int end = 0; 
     
    508521          else if (args[i].equals("-nocolors")) ignoreColors = true; 
    509522          else if (args[i].equals("-omexml")) omexml = true; 
     523          else if (args[i].equals("-normalize")) normalize = true; 
    510524          else if (args[i].equals("-range")) { 
    511525            try { 
     
    550564      System.out.println("   -range: specify range of planes to read"); 
    551565      System.out.println("  -series: specify which image series to read"); 
     566      System.out.println("   -normalize: normalize floating point images " + 
     567        "(may result in loss of precision)"); 
     568      System.out.println("    -fast: paint RGB images as quickly as possible" + 
     569        "(may result in loss of precision)"); 
    552570      System.out.println(); 
    553571      return false; 
     
    585603 
    586604    reader.setIgnoreColorTable(ignoreColors); 
     605    reader.setNormalize(normalize); 
     606 
     607    if (!normalize && reader.getPixelType(id) == FLOAT && !reader.isRGB(id)) { 
     608      throw new FormatException("Sorry, unnormalized grayscale floating " + 
     609        "point data is not supported.  Please use the '-normalize' option."); 
     610    } 
     611 
    587612 
    588613    // read basic metadata 
  • trunk/loci/formats/IFormatReader.java

    r1747 r1806  
    185185  void setIgnoreColorTable(boolean ignore); 
    186186 
     187  /** Specify whether or not to normalize float data. */ 
     188  void setNormalize(boolean normalize); 
     189 
     190  /** Return true if we should normalize float data. */ 
     191  boolean getNormalize(); 
     192 
    187193  /** 
    188194   * Swaps the dimensions according to the given dimension order.  If the given 
  • trunk/loci/formats/ImageReader.java

    r1786 r1806  
    355355    for (int i=0; i<readers.length; i++) readers[i].setIgnoreColorTable(ignore); 
    356356  } 
     357 
     358  /* @see IFormatReader#setNormalize(boolean) */ 
     359  public void setNormalize(boolean normalize) { 
     360    for (int i=0; i<readers.length; i++) readers[i].setNormalize(normalize); 
     361  } 
     362 
     363  /* @see IFormatReader#getNormalize() */ 
     364  public boolean getNormalize() { return readers[0].getNormalize(); } 
    357365 
    358366  /** 
  • trunk/loci/formats/ImageTools.java

    r1777 r1806  
    6262    boolean interleaved, int bps, boolean little) 
    6363  { 
    64     if (bps == 1) return makeImage(data, w, h, c, interleaved); 
    65     else if (bps == 2) { 
    66       short[] shorts = new short[data.length / bps]; 
    67       for (int i=0; i<shorts.length; i++) { 
    68         shorts[i] = DataTools.bytesToShort(data, i*2, 2, little); 
    69       } 
    70       return makeImage(shorts, w, h, c, interleaved); 
    71     } 
    72     else if (bps == 3) { 
    73       return ImageTools.makeImage(data, w, h, 3, interleaved); 
    74     } 
    75     else if (bps == 4) { 
    76       int[] ints = new int[data.length / bps]; 
    77       for (int i=0; i<ints.length; i++) { 
    78         ints[i] = DataTools.bytesToInt(data, i*4, 4, little); 
    79       } 
    80       return makeImage(ints, w, h, c, interleaved); 
    81     } 
    82     else if (bps == 6) { 
    83       short[][] shorts = new short[3][data.length / 6]; 
    84       int next = 0; 
    85       if (interleaved) { 
    86         for (int i=0; i<shorts[0].length; i++) { 
    87           for (int j=0; j<shorts.length; j++) { 
    88             shorts[j][i] = DataTools.bytesToShort(data, next, 2, little); 
    89             next += 2; 
    90           } 
    91         } 
    92       } 
    93       else { 
    94         for (int i=0; i<shorts.length; i++) { 
    95           for (int j=0; j<shorts[i].length; j++) { 
    96             shorts[i][j] = DataTools.bytesToShort(data, next, 2, little); 
    97             next += 2; 
    98           } 
    99         } 
    100       } 
    101       return makeImage(shorts, w, h); 
    102     } 
    103     else { 
    104       double[] doubles = new double[data.length / bps]; 
    105       for (int i=0; i<doubles.length; i++) { 
    106         doubles[i] = Double.longBitsToDouble( 
    107           DataTools.bytesToLong(data, i*bps, bps, little)); 
    108       } 
    109       return makeImage(doubles, w, h, c, interleaved); 
    110     } 
    111   } 
    112  
    113   /** 
    114    * Creates an image from the given unsigned byte data. 
    115    * If the interleaved flag is set, the channels are assumed to be 
    116    * interleaved; otherwise they are assumed to be sequential. 
    117    * For example, for RGB data, the pattern "RGBRGBRGB..." is interleaved, 
    118    * while "RRR...GGG...BBB..." is sequential. 
    119    */ 
    120   public static BufferedImage makeImage(byte[] data, 
    121     int w, int h, int c, boolean interleaved) 
    122   { 
    123     if (c == 1) return makeImage(data, w, h); 
    124     int dataType = DataBuffer.TYPE_BYTE; 
    125     ColorModel colorModel = makeColorModel(c, dataType); 
    126     if (colorModel == null) return null; 
    127     int pixelStride = interleaved ? c : 1; 
    128     int scanlineStride = interleaved ? (c * w) : w; 
    129     int[] bandOffsets = new int[c]; 
    130     for (int i=0; i<c; i++) bandOffsets[i] = interleaved ? i : (i * w * h); 
    131     SampleModel model = new ComponentSampleModel(dataType, 
    132       w, h, pixelStride, scanlineStride, bandOffsets); 
    133     DataBuffer buffer = new DataBufferByte(data, c * w * h); 
    134     WritableRaster raster = Raster.createWritableRaster(model, buffer, null); 
    135     return new BufferedImage(colorModel, raster, false, null); 
    136   } 
    137  
    138   /** 
    139    * Creates an image from the given unsigned short data. 
    140    * If the interleaved flag is set, the channels are assumed to be 
    141    * interleaved; otherwise they are assumed to be sequential. 
    142    * For example, for RGB data, the pattern "RGBRGBRGB..." is interleaved, 
    143    * while "RRR...GGG...BBB..." is sequential. 
    144    */ 
    145   public static BufferedImage makeImage(short[] data, 
    146     int w, int h, int c, boolean interleaved) 
    147   { 
    148     if (c == 1) return makeImage(data, w, h); 
    149     int dataType = DataBuffer.TYPE_USHORT; 
    150     ColorModel colorModel = makeColorModel(c, dataType); 
    151     if (colorModel == null) return null; 
    152     int pixelStride = interleaved ? c : 1; 
    153     int scanlineStride = interleaved ? (c * w) : w; 
    154     int[] bandOffsets = new int[c]; 
    155     for (int i=0; i<c; i++) bandOffsets[i] = interleaved ? i : (i * w * h); 
    156     SampleModel model = new ComponentSampleModel(dataType, 
    157       w, h, pixelStride, scanlineStride, bandOffsets); 
    158     DataBuffer buffer = new DataBufferUShort(data, c * w * h); 
    159     WritableRaster raster = Raster.createWritableRaster(model, buffer, null); 
    160     return new BufferedImage(colorModel, raster, false, null); 
    161   } 
    162  
    163   /** 
    164    * Creates an image from the given signed int data. 
    165    * If the interleaved flag is set, the channels are assumed to be 
    166    * interleaved; otherwise they are assumed to be sequential. 
    167    * For example, for RGB data, the pattern "RGBRGBRGB..." is interleaved, 
    168    * while "RRR...GGG...BBB..." is sequential. 
    169    */ 
    170   public static BufferedImage makeImage(int[] data, 
    171     int w, int h, int c, boolean interleaved) 
    172   { 
    173     if (c == 1) return makeImage(data, w, h); 
    174     int dataType = DataBuffer.TYPE_INT; 
    175     ColorModel colorModel = makeColorModel(c, dataType); 
    176     if (colorModel == null) return null; 
    177     int pixelStride = interleaved ? c : 1; 
    178     int scanlineStride = interleaved ? (c * w) : w; 
    179     int[] bandOffsets = new int[c]; 
    180     for (int i=0; i<c; i++) bandOffsets[i] = interleaved ? i : (i * w * h); 
    181     SampleModel model = new ComponentSampleModel(dataType, 
    182       w, h, pixelStride, scanlineStride, bandOffsets); 
    183     DataBuffer buffer = new DataBufferInt(data, c * w * h); 
    184     WritableRaster raster = Raster.createWritableRaster(model, buffer, null); 
    185     return new BufferedImage(colorModel, raster, false, null); 
    186   } 
    187  
    188   /** 
    189    * Creates an image from the given float data. 
    190    * If the interleaved flag is set, the channels are assumed to be 
    191    * interleaved; otherwise they are assumed to be sequential. 
    192    * For example, for RGB data, the pattern "RGBRGBRGB..." is interleaved, 
    193    * while "RRR...GGG...BBB..." is sequential. 
    194    */ 
    195   public static BufferedImage makeImage(float[] data, 
    196     int w, int h, int c, boolean interleaved) 
    197   { 
    198     if (c == 1) return makeImage(data, w, h); 
    199     int dataType = DataBuffer.TYPE_FLOAT; 
    200     ColorModel colorModel = makeColorModel(c, dataType); 
    201     if (colorModel == null) return null; 
    202     int pixelStride = interleaved ? c : 1; 
    203     int scanlineStride = interleaved ? (c * w) : w; 
    204     int[] bandOffsets = new int[c]; 
    205     for (int i=0; i<c; i++) bandOffsets[i] = interleaved ? i : (i * w * h); 
    206     SampleModel model = new ComponentSampleModel(dataType, 
    207       w, h, pixelStride, scanlineStride, bandOffsets); 
    208     DataBuffer buffer = new DataBufferFloat(data, c * w * h); 
    209     WritableRaster raster = Raster.createWritableRaster(model, buffer, null); 
    210     return new BufferedImage(colorModel, raster, false, null); 
    211   } 
    212  
    213   /** 
    214    * Creates an image from the given double data. 
    215    * If the interleaved flag is set, the channels are assumed to be 
    216    * interleaved; otherwise they are assumed to be sequential. 
    217    * For example, for RGB data, the pattern "RGBRGBRGB..." is interleaved, 
    218    * while "RRR...GGG...BBB..." is sequential. 
    219    */ 
    220   public static BufferedImage makeImage(double[] data, 
    221     int w, int h, int c, boolean interleaved) 
    222   { 
    223     if (c == 1) return makeImage(data, w, h); 
    224     int dataType = DataBuffer.TYPE_DOUBLE; 
    225     ColorModel colorModel = makeColorModel(c, dataType); 
    226     if (colorModel == null) return null; 
    227     int pixelStride = interleaved ? c : 1; 
    228     int scanlineStride = interleaved ? (c * w) : w; 
    229     int[] bandOffsets = new int[c]; 
    230     for (int i=0; i<c; i++) bandOffsets[i] = interleaved ? i : (i * w * h); 
    231     SampleModel model = new ComponentSampleModel(dataType, 
    232       w, h, pixelStride, scanlineStride, bandOffsets); 
    233     DataBuffer buffer = new DataBufferDouble(data, c * w * h); 
    234     WritableRaster raster = Raster.createWritableRaster(model, buffer, null); 
    235     return new BufferedImage(colorModel, raster, false, null); 
     64    return makeImage(data, w, h, c, interleaved, bps, little, null); 
    23665  } 
    23766 
     
    24372   * For example, for RGB data, the pattern "RGBRGBRGB..." is interleaved, 
    24473   * while "RRR...GGG...BBB..." is sequential. 
     74   * 
     75   * The 'bits' argument specifies the number of significant bits per 
     76   * color component; if it is null, then all of the bits are used. 
     77   */ 
     78  public static BufferedImage makeImage(byte[] data, int w, int h, int c, 
     79    boolean interleaved, int bps, boolean little, int[] bits) 
     80  { 
     81    Object pixels = DataTools.makeDataArray(data, bps % 3 == 0 ? bps / 3 : bps, 
     82      false, little); 
     83 
     84    if (pixels instanceof byte[]) { 
     85      return makeImage((byte[]) pixels, w, h, c, interleaved, bits); 
     86    } 
     87    else if (pixels instanceof short[]) { 
     88      return makeImage((short[]) pixels, w, h, c, interleaved, bits); 
     89    } 
     90    else if (pixels instanceof int[]) { 
     91      return makeImage((int[]) pixels, w, h, c, interleaved, bits); 
     92    } 
     93    else if (pixels instanceof float[]) { 
     94      return makeImage((float[]) pixels, w, h, c, interleaved, bits); 
     95    } 
     96    else if (pixels instanceof double[]) { 
     97      return makeImage((double[]) pixels, w, h, c, interleaved, bits); 
     98    } 
     99    return null; 
     100  } 
     101 
     102  /** 
     103   * Creates an image from the given unsigned byte data. 
     104   * If the interleaved flag is set, the channels are assumed to be 
     105   * interleaved; otherwise they are assumed to be sequential. 
     106   * For example, for RGB data, the pattern "RGBRGBRGB..." is interleaved, 
     107   * while "RRR...GGG...BBB..." is sequential. 
     108   */ 
     109  public static BufferedImage makeImage(byte[] data, 
     110    int w, int h, int c, boolean interleaved) 
     111  { 
     112    return makeImage(data, w, h, c, interleaved, null); 
     113  } 
     114 
     115  /** 
     116   * Creates an image from the given unsigned byte data. 
     117   * If the interleaved flag is set, the channels are assumed to be 
     118   * interleaved; otherwise they are assumed to be sequential. 
     119   * For example, for RGB data, the pattern "RGBRGBRGB..." is interleaved, 
     120   * while "RRR...GGG...BBB..." is sequential. 
     121   * 
     122   * The 'bits' argument specifies the number of significant bits per 
     123   * color component; if it is null, then all of the bits are used. 
     124   */ 
     125  public static BufferedImage makeImage(byte[] data, 
     126    int w, int h, int c, boolean interleaved, int[] bits) 
     127  { 
     128    if (c == 1) return makeImage(data, w, h, bits); 
     129    int dataType = DataBuffer.TYPE_BYTE; 
     130    if (c == 2) { 
     131      byte[] tmp = data; 
     132      data = new byte[(tmp.length / 2) * 3]; 
     133      if (interleaved) { 
     134        for (int i=0; i<tmp.length/2; i++) { 
     135          data[i*3] = tmp[i*2]; 
     136          data[i*3 + 1] = tmp[i*2 + 1]; 
     137        } 
     138      } 
     139      else System.arraycopy(tmp, 0, data, 0, tmp.length); 
     140      c++; 
     141    } 
     142    DataBuffer buffer = new DataBufferByte(data, c * w * h); 
     143    return constructImage(c, dataType, w, h, interleaved, buffer, bits); 
     144  } 
     145 
     146  /** 
     147   * Creates an image from the given unsigned short data. 
     148   * If the interleaved flag is set, the channels are assumed to be 
     149   * interleaved; otherwise they are assumed to be sequential. 
     150   * For example, for RGB data, the pattern "RGBRGBRGB..." is interleaved, 
     151   * while "RRR...GGG...BBB..." is sequential. 
     152   */ 
     153  public static BufferedImage makeImage(short[] data, 
     154    int w, int h, int c, boolean interleaved) 
     155  { 
     156    return makeImage(data, w, h, c, interleaved, null); 
     157  } 
     158 
     159  /** 
     160   * Creates an image from the given unsigned short data. 
     161   * If the interleaved flag is set, the channels are assumed to be 
     162   * interleaved; otherwise they are assumed to be sequential. 
     163   * For example, for RGB data, the pattern "RGBRGBRGB..." is interleaved, 
     164   * while "RRR...GGG...BBB..." is sequential. 
     165   * 
     166   * The 'bits' argument specifies the number of significant bits per 
     167   * color component; if it is null, then all of the bits are used. 
     168   */ 
     169  public static BufferedImage makeImage(short[] data, 
     170    int w, int h, int c, boolean interleaved, int[] bits) 
     171  { 
     172    if (c == 1) return makeImage(data, w, h, bits); 
     173    int dataType = DataBuffer.TYPE_USHORT; 
     174    if (c == 2) { 
     175      short[] tmp = data; 
     176      data = new short[(tmp.length / 2) * 3]; 
     177      if (interleaved) { 
     178        for (int i=0; i<tmp.length/2; i++) { 
     179          data[i*3] = tmp[i*2]; 
     180          data[i*3 + 1] = tmp[i*2 + 1]; 
     181        } 
     182      } 
     183      else System.arraycopy(tmp, 0, data, 0, tmp.length); 
     184      c++; 
     185    } 
     186    DataBuffer buffer = new DataBufferUShort(data, c * w * h); 
     187    return constructImage(c, dataType, w, h, interleaved, buffer, bits); 
     188  } 
     189 
     190  /** 
     191   * Creates an image from the given signed int data. 
     192   * If the interleaved flag is set, the channels are assumed to be 
     193   * interleaved; otherwise they are assumed to be sequential. 
     194   * For example, for RGB data, the pattern "RGBRGBRGB..." is interleaved, 
     195   * while "RRR...GGG...BBB..." is sequential. 
     196   */ 
     197  public static BufferedImage makeImage(int[] data, 
     198    int w, int h, int c, boolean interleaved) 
     199  { 
     200    return makeImage(data, w, h, c, interleaved, null); 
     201  } 
     202 
     203  /** 
     204   * Creates an image from the given signed int data. 
     205   * If the interleaved flag is set, the channels are assumed to be 
     206   * interleaved; otherwise they are assumed to be sequential. 
     207   * For example, for RGB data, the pattern "RGBRGBRGB..." is interleaved, 
     208   * while "RRR...GGG...BBB..." is sequential. 
     209   * 
     210   * The 'bits' argument specifies the number of significant bits per 
     211   * color component; if it is null, then all of the bits are used. 
     212   */ 
     213  public static BufferedImage makeImage(int[] data, 
     214    int w, int h, int c, boolean interleaved, int[] bits) 
     215  { 
     216    if (c == 1) return makeImage(data, w, h, bits); 
     217    int dataType = DataBuffer.TYPE_INT; 
     218    if (c == 2) { 
     219      int[] tmp = data; 
     220      data = new int[(tmp.length / 2) * 3]; 
     221      if (interleaved) { 
     222        for (int i=0; i<tmp.length/2; i++) { 
     223          data[i*3] = tmp[i*2]; 
     224          data[i*3 + 1] = tmp[i*2 + 1]; 
     225        } 
     226      } 
     227      else System.arraycopy(tmp, 0, data, 0, tmp.length); 
     228      c++; 
     229    } 
     230    DataBuffer buffer = new DataBufferInt(data, c * w * h); 
     231    return constructImage(c, dataType, w, h, interleaved, buffer, bits); 
     232  } 
     233 
     234  /** 
     235   * Creates an image from the given float data. 
     236   * If the interleaved flag is set, the channels are assumed to be 
     237   * interleaved; otherwise they are assumed to be sequential. 
     238   * For example, for RGB data, the pattern "RGBRGBRGB..." is interleaved, 
     239   * while "RRR...GGG...BBB..." is sequential. 
     240   */ 
     241  public static BufferedImage makeImage(float[] data, 
     242    int w, int h, int c, boolean interleaved) 
     243  { 
     244    return makeImage(data, w, h, c, interleaved, null); 
     245  } 
     246 
     247  /** 
     248   * Creates an image from the given float data. 
     249   * If the interleaved flag is set, the channels are assumed to be 
     250   * interleaved; otherwise they are assumed to be sequential. 
     251   * For example, for RGB data, the pattern "RGBRGBRGB..." is interleaved, 
     252   * while "RRR...GGG...BBB..." is sequential. 
     253   * 
     254   * The 'bits' argument specifies the number of significant bits per 
     255   * color component; if it is null, then all of the bits are used. 
     256   */ 
     257  public static BufferedImage makeImage(float[] data, 
     258    int w, int h, int c, boolean interleaved, int[] bits) 
     259  { 
     260    if (c == 1) return makeImage(data, w, h, bits); 
     261    int dataType = DataBuffer.TYPE_FLOAT; 
     262    if (c == 2) { 
     263      float[] tmp = data; 
     264      data = new float[(tmp.length / 2) * 3]; 
     265      if (interleaved) { 
     266        for (int i=0; i<tmp.length/2; i++) { 
     267          data[i*3] = tmp[i*2]; 
     268          data[i*3 + 1] = tmp[i*2 + 1]; 
     269        } 
     270      } 
     271      else System.arraycopy(tmp, 0, data, 0, tmp.length); 
     272      c++; 
     273    } 
     274    DataBuffer buffer = new DataBufferFloat(data, c * w * h); 
     275    return constructImage(c, dataType, w, h, interleaved, buffer, bits); 
     276  } 
     277 
     278  /** 
     279   * Creates an image from the given double data. 
     280   * If the interleaved flag is set, the channels are assumed to be 
     281   * interleaved; otherwise they are assumed to be sequential. 
     282   * For example, for RGB data, the pattern "RGBRGBRGB..." is interleaved, 
     283   * while "RRR...GGG...BBB..." is sequential. 
     284   */ 
     285  public static BufferedImage makeImage(double[] data, 
     286    int w, int h, int c, boolean interleaved) 
     287  { 
     288    return makeImage(data, w, h, c, interleaved, null); 
     289  } 
     290 
     291  /** 
     292   * Creates an image from the given double data. 
     293   * If the interleaved flag is set, the channels are assumed to be 
     294   * interleaved; otherwise they are assumed to be sequential. 
     295   * For example, for RGB data, the pattern "RGBRGBRGB..." is interleaved, 
     296   * while "RRR...GGG...BBB..." is sequential. 
     297   * 
     298   * The 'bits' argument specifies the number of significant bits per 
     299   * color component; if it is null, then all of the bits are used. 
     300   */ 
     301  public static BufferedImage makeImage(double[] data, 
     302    int w, int h, int c, boolean interleaved, int[] bits) 
     303  { 
     304 
     305    if (c == 1) return makeImage(data, w, h, bits); 
     306    int dataType = DataBuffer.TYPE_DOUBLE; 
     307    if (c == 2) { 
     308      double[] tmp = data; 
     309      data = new double[(tmp.length / 2) * 3]; 
     310      if (interleaved) { 
     311        for (int i=0; i<tmp.length/2; i++) { 
     312          data[i*3] = tmp[i*2]; 
     313          data[i*3 + 1] = tmp[i*2 + 1]; 
     314        } 
     315      } 
     316      else System.arraycopy(tmp, 0, data, 0, tmp.length); 
     317      c++; 
     318    } 
     319    DataBuffer buffer = new DataBufferDouble(data, c * w * h); 
     320    return constructImage(c, dataType, w, h, interleaved, buffer, bits); 
     321  } 
     322 
     323  /** 
     324   * Creates an image from the given data, performing type conversions as 
     325   * necessary. 
     326   * If the interleaved flag is set, the channels are assumed to be 
     327   * interleaved; otherwise they are assumed to be sequential. 
     328   * For example, for RGB data, the pattern "RGBRGBRGB..." is interleaved, 
     329   * while "RRR...GGG...BBB..." is sequential. 
    245330   */ 
    246331  public static BufferedImage makeImage(byte[][] data, int w, int h, 
    247332    int bps, boolean little) 
    248333  { 
    249     if (bps == 1) return makeImage(data, w, h); 
     334    return makeImage(data, w, h, bps, little, null); 
     335  } 
     336 
     337  /** 
     338   * Creates an image from the given data, performing type conversions as 
     339   * necessary. 
     340   * If the interleaved flag is set, the channels are assumed to be 
     341   * interleaved; otherwise they are assumed to be sequential. 
     342   * For example, for RGB data, the pattern "RGBRGBRGB..." is interleaved, 
     343   * while "RRR...GGG...BBB..." is sequential. 
     344   * 
     345   * The 'bits' argument specifies the number of significant bits per 
     346   * color component; if it is null, then all of the bits are used. 
     347   */ 
     348  public static BufferedImage makeImage(byte[][] data, int w, int h, 
     349    int bps, boolean little, int[] bits) 
     350  { 
     351    if (bps == 1) return makeImage(data, w, h, bits); 
    250352    else if (bps == 2) { 
    251353      short[][] shorts = new short[data.length][data[0].length / bps]; 
     
    255357        } 
    256358      } 
    257       return makeImage(shorts, w, h); 
     359      return makeImage(shorts, w, h, bits); 
    258360    } 
    259361    else if (bps == 4) { 
     
    265367        } 
    266368      } 
    267       return makeImage(floats, w, h); 
     369      return makeImage(floats, w, h, bits); 
    268370    } 
    269371    else { 
     
    275377        } 
    276378      } 
    277       return makeImage(doubles, w, h); 
     379      return makeImage(doubles, w, h, bits); 
    278380    } 
    279381  } 
     
    285387   */ 
    286388  public static BufferedImage makeImage(byte[][] data, int w, int h) { 
     389    return makeImage(data, w, h, null); 
     390  } 
     391 
     392  /** 
     393   * Creates an image from the given unsigned byte data. 
     394   * It is assumed that each channel corresponds to one element of the array. 
     395   * For example, for RGB data, data[0] is R, data[1] is G, and data[2] is B. 
     396   * 
     397   * The 'bits' argument specifies the number of significant bits per 
     398   * color component; if it is null, then all of the bits are used. 
     399   */ 
     400  public static BufferedImage makeImage(byte[][] data, int w, int h, int[] bits) 
     401  { 
    287402    int dataType = DataBuffer.TYPE_BYTE; 
    288     ColorModel colorModel = makeColorModel(data.length, dataType); 
     403    ColorModel colorModel = makeColorModel(data.length, dataType, bits); 
    289404    if (colorModel == null) return null; 
    290405    SampleModel model = new BandedSampleModel(dataType, w, h, data.length); 
     
    300415   */ 
    301416  public static BufferedImage makeImage(short[][] data, int w, int h) { 
     417    return makeImage(data, w, h, null); 
     418  } 
     419 
     420  /** 
     421   * Creates an image from the given unsigned short data. 
     422   * It is assumed that each channel corresponds to one element of the array. 
     423   * For example, for RGB data, data[0] is R, data[1] is G, and data[2] is B. 
     424   * 
     425   * The 'bits' argument specifies the number of significant bits per 
     426   * color component; if it is null, then all of the bits are used. 
     427   */ 
     428  public static BufferedImage makeImage(short[][] data, int w, int h, 
     429    int[] bits) 
     430  { 
    302431    int dataType = DataBuffer.TYPE_USHORT; 
    303     ColorModel colorModel = makeColorModel(data.length, dataType); 
     432    ColorModel colorModel = makeColorModel(data.length, dataType, bits); 
    304433    if (colorModel == null) return null; 
    305434    SampleModel model = new BandedSampleModel(dataType, w, h, data.length); 
     
    315444   */ 
    316445  public static BufferedImage makeImage(int[][] data, int w, int h) { 
     446    return makeImage(data, w, h, null); 
     447  } 
     448 
     449  /** 
     450   * Creates an image from the given signed int data. 
     451   * It is assumed that each channel corresponds to one element of the array. 
     452   * For example, for RGB data, data[0] is R, data[1] is G, and data[2] is B. 
     453   * 
     454   * The 'bits' argument specifies the number of significant bits per 
     455   * color component; if it is null, then all of the bits are used. 
     456   */ 
     457  public static BufferedImage makeImage(int[][] data, int w, int h, int[] bits) 
     458  { 
    317459    int dataType = DataBuffer.TYPE_INT; 
    318     ColorModel colorModel = makeColorModel(data.length, dataType); 
     460    ColorModel colorModel = makeColorModel(data.length, dataType, bits); 
    319461    if (colorModel == null) return null; 
    320462    SampleModel model = new BandedSampleModel(dataType, w, h, data.length); 
     
    330472   */ 
    331473  public static BufferedImage makeImage(float[][] data, int w, int h) { 
     474    return makeImage(data, w, h, null); 
     475  } 
     476 
     477  /** 
     478   * Creates an image from the given single-precision floating point data. 
     479   * It is assumed that each channel corresponds to one element of the array. 
     480   * For example, for RGB data, data[0] is R, data[1] is G, and data[2] is B. 
     481   * 
     482   * The 'bits' argument specifies the number of significant bits per 
     483   * color component; if it is null, then all of the bits are used. 
     484   */ 
     485  public static BufferedImage makeImage(float[][] data, int w, int h, 
     486    int[] bits) 
     487  { 
    332488    int dataType = DataBuffer.TYPE_FLOAT; 
    333     ColorModel colorModel = makeColorModel(data.length, dataType); 
     489    ColorModel colorModel = makeColorModel(data.length, dataType, bits); 
    334490    if (colorModel == null) return null; 
    335491    SampleModel model = new BandedSampleModel(dataType, w, h, data.length); 
     
    345501   */ 
    346502  public static BufferedImage makeImage(double[][] data, int w, int h) { 
     503    return makeImage(data, w, h, null); 
     504  } 
     505 
     506  /** 
     507   * Creates an image from the given double-precision floating point data. 
     508   * It is assumed that each channel corresponds to one element of the array. 
     509   * For example, for RGB data, data[0] is R, data[1] is G, and data[2] is B. 
     510   * 
     511   * The 'bits' argument specifies the number of significant bits per 
     512   * color component; if it is null, then all of the bits are used. 
     513   */ 
     514  public static BufferedImage makeImage(double[][] data, int w, int h, 
     515    int[] bits) 
     516  { 
    347517    int dataType = DataBuffer.TYPE_DOUBLE; 
    348     ColorModel colorModel = makeColorModel(data.length, dataType); 
     518    ColorModel colorModel = makeColorModel(data.length, dataType, bits); 
    349519    if (colorModel == null) return null; 
    350520    SampleModel model = new BandedSampleModel(dataType, w, h, data.length); 
     
    356526  /** Creates an image from the given single-channel unsigned byte data. */ 
    357527  public static BufferedImage makeImage(byte[] data, int w, int h) { 
    358     return makeImage(new byte[][] {data}, w, h); 
     528    return makeImage(data, w, h, null); 
     529  } 
     530 
     531  /** 
     532   * Creates an image from the given single-channel unsigned byte data. 
     533   * The 'bits' argument specifies the number of significant bits per 
     534   * color component; if it is null, then all of the bits are used. 
     535   */ 
     536  public static BufferedImage makeImage(byte[] data, int w, int h, int[] bits) { 
     537    return makeImage(new byte[][] {data}, w, h, bits); 
    359538  } 
    360539 
    361540  /** Creates an image from the given single-channel unsigned short data. */ 
    362541  public static BufferedImage makeImage(short[] data, int w, int h) { 
    363     return makeImage(new short[][] {data}, w, h); 
     542    return makeImage(data, w, h, null); 
     543  } 
     544 
     545  /** 
     546   * Creates an image from the given single-channel unsigned short data. 
     547   * The 'bits' argument specifies the number of significant bits per 
     548   * color component; if it is null, then all of the bits are used. 
     549   */ 
     550  public static BufferedImage makeImage(short[] data, int w, int h, int[] bits) 
     551  { 
     552    return makeImage(new short[][] {data}, w, h, bits); 
    364553  } 
    365554 
    366555  /** Creates an image from the given single-channel signed int data. */ 
    367556  public static BufferedImage makeImage(int[] data, int w, int h) { 
    368     return makeImage(new int[][] {data}, w, h); 
     557    return makeImage(data, w, h, null); 
     558  } 
     559 
     560  /** 
     561   * Creates an image from the given single-channel signed int data. 
     562   * The 'bits' argument specifies the number of significant bits per 
     563   * color component; if it is null, then all of the bits are used. 
     564   */ 
     565  public static BufferedImage makeImage(int[] data, int w, int h, int[] bits) { 
     566    return makeImage(new int[][] {data}, w, h, bits); 
    369567  } 
    370568 
    371569  /** Creates an image from the given single-channel float data. */ 
    372570  public static BufferedImage makeImage(float[] data, int w, int h) { 
    373     return makeImage(new float[][] {data}, w, h); 
     571    return makeImage(data, w, h, null); 
     572  } 
     573 
     574  /** 
     575   * Creates an image from the given single-channel double data. 
     576   * The 'bits' argument specifies the number of significant bits per 
     577   * color component; if it is null, then all of the bits are used. 
     578   */ 
     579  public static BufferedImage makeImage(float[] data, int w, int h, int[] bits) 
     580  { 
     581    return makeImage(new float[][] {data}, w, h, bits); 
    374582  } 
    375583 
    376584  /** Creates an image from the given single-channel double data. */ 
    377585  public static BufferedImage makeImage(double[] data, int w, int h) { 
    378     return makeImage(new double[][] {data}, w, h); 
     586    return makeImage(data, w, h, null); 
     587  } 
     588 
     589  /** 
     590   * Creates an image from the given single-channel double data. 
     591   * The 'bits' argument specifies the number of significant bits per 
     592   * color component; if it is null, then all of the bits are used. 
     593   */ 
     594  public static BufferedImage makeImage(double[] data, int w, int h, int[] bits) 
     595  { 
     596    return makeImage(new double[][] {data}, w, h, bits); 
     597  } 
     598 
     599  /** Create a blank image with the given dimensions and transfer type. */ 
     600  public static BufferedImage blankImage(int w, int h, int c, int type) 
     601  { 
     602    int tt = 0; 
     603    DataBuffer buffer = null; 
     604    switch (type) { 
     605      case FormatReader.INT8: 
     606      case FormatReader.UINT8: 
     607        tt = DataBuffer.TYPE_BYTE; 
     608        buffer = new DataBufferByte(new byte[c * w * h], c * w * h); 
     609        break; 
     610      case FormatReader.INT16: 
     611      case FormatReader.UINT16: 
     612        tt = DataBuffer.TYPE_USHORT; 
     613        buffer = new DataBufferUShort(new short[c * w * h], c * w * h); 
     614        break; 
     615      case FormatReader.INT32: 
     616      case FormatReader.UINT32: 
     617        tt = DataBuffer.TYPE_INT; 
     618        buffer = new DataBufferInt(new int[c * w * h], c * w * h); 
     619        break; 
     620      case FormatReader.FLOAT: 
     621        tt = DataBuffer.TYPE_FLOAT; 
     622        buffer = new DataBufferFloat(new float[c * w * h], c * w * h); 
     623        break; 
     624      case FormatReader.DOUBLE: 
     625        tt = DataBuffer.TYPE_DOUBLE; 
     626        buffer = new DataBufferDouble(new double[c * w * h], c * w * h); 
     627        break; 
     628    } 
     629 
     630    return constructImage(c, tt, w, h, true, buffer, null); 
     631  } 
     632 
     633  /** Create an image with the given DataBuffer. */ 
     634  private static BufferedImage constructImage(int c, int type, int w, 
     635    int h, boolean interleaved, DataBuffer buffer, int[] bits) 
     636  { 
     637    ColorModel colorModel = makeColorModel(c, type, bits); 
     638    if (colorModel == null) return null; 
     639    int pixelStride = interleaved ? c : 1; 
     640    int scanlineStride = interleaved ? (c * w) : w; 
     641    if (c == 2) c++; 
     642    int[] bandOffsets = new int[c]; 
     643    for (int i=0; i<c; i++) bandOffsets[i] = interleaved ? i : (i * w * h); 
     644 
     645    SampleModel model = new ComponentSampleModel(type, w, h, pixelStride, 
     646      scanlineStride, bandOffsets); 
     647 
     648    WritableRaster raster = Raster.createWritableRaster(model, buffer, null); 
     649    return new BufferedImage(colorModel, raster, false, null); 
    379650  } 
    380651 
     
    415686    // convert to image with DataBufferByte and BandedSampleModel 
    416687    int w = image.getWidth(), h = image.getHeight(), c = r.getNumBands(); 
    417     ColorModel colorModel = makeColorModel(c, dataType); 
     688    ColorModel colorModel = makeColorModel(c, dataType, null); 
    418689    if (colorModel == null) return null; 
    419690    SampleModel model = new BandedSampleModel(dataType, w, h, c); 
     
    458729      } 
    459730    } 
    460      
     731 
    461732    int w = image.getWidth(), h = image.getHeight(), c = r.getNumBands(); 
    462733    int[][] samples = new int[c][w * h]; 
    463734    for (int i=0; i<c; i++) r.getSamples(0, 0, w, h, i, samples[i]); 
    464735    return samples; 
    465     //return getInts(makeType(image, DataBuffer.TYPE_INT)); 
    466736  } 
    467737 
     
    485755    for (int i=0; i<c; i++) r.getSamples(0, 0, w, h, i, samples[i]); 
    486756    return samples; 
    487     //return getFloats(makeType(image, DataBuffer.TYPE_FLOAT)); 
    488757  } 
    489758 
     
    507776    for (int i=0; i<c; i++) r.getSamples(0, 0, w, h, i, samples[i]); 
    508777    return samples; 
    509     //return getDoubles(makeType(image, DataBuffer.TYPE_DOUBLE)); 
    510778  } 
    511779 
     
    607875    WritableRaster r = image.getRaster(); 
    608876    int w = image.getWidth(), h = image.getHeight(), c = r.getNumBands(); 
    609     ColorModel colorModel = makeColorModel(c, type); 
     877    ColorModel colorModel = makeColorModel(c, type, null); 
    610878    if (colorModel == null) return null; 
    611879 
     
    644912  } 
    645913 
     914  /** 
     915   * Convert an arbitrary primitive type array with 3 samples per pixel to 
     916   * an int array, i.e. RGB color with 8 bits per pixel. 
     917   * Does not perform any scaling. 
     918   */ 
     919  public static int[] make24Bits(Object pixels, int w, int h, 
     920    boolean interleaved) 
     921  { 
     922    int[] rtn = new int[w * h]; 
     923    int stride = interleaved ? w * h : 1; 
     924    int mul = interleaved ? 1 : 3; 
     925    if (pixels instanceof byte[]) { 
     926      byte[] b = (byte[]) pixels; 
     927      for (int i=0; i<rtn.length; i++) { 
     928        byte[] a = new byte[] {0, b[i*mul], b[i*mul + stride], 
     929          b[i*mul + 2*stride]}; 
     930        rtn[i] = DataTools.bytesToInt(a, false); 
     931      } 
     932      b = null; 
     933    } 
     934    else if (pixels instanceof short[]) { 
     935      short[] s = (short[]) pixels; 
     936      for (int i=0; i<rtn.length; i++) { 
     937        byte[] a = new byte[] {0, (byte) s[i*mul], (byte) s[i*mul + stride], 
     938          (byte) s[i*mul + 2*stride]}; 
     939        rtn[i] = DataTools.bytesToInt(a, false); 
     940      } 
     941      s = null; 
     942    } 
     943    else if (pixels instanceof int[]) { 
     944      int[] in = (int[]) pixels; 
     945      for (int i=0; i<rtn.length; i++) { 
     946        byte[] a = new byte[] {0, (byte) in[i*mul], (byte) in[i*mul + stride], 
     947          (byte) in[i*mul + 2*stride]}; 
     948        rtn[i] = DataTools.bytesToInt(a, false); 
     949      } 
     950      in = null; 
     951    } 
     952    else if (pixels instanceof float[]) { 
     953      float[] f = (float[]) pixels; 
     954      for (int i=0; i<rtn.length; i++) { 
     955        byte[] a = new byte[] { 
     956          0, (byte) Float.floatToIntBits(f[i*mul]), 
     957          (byte) Float.floatToIntBits(f[i*mul + stride]), 
     958          (byte) Float.floatToIntBits(f[i*mul + 2*stride])}; 
     959        rtn[i] = DataTools.bytesToInt(a, false); 
     960      } 
     961      f = null; 
     962    } 
     963    else if (pixels instanceof double[]) { 
     964      double[] d = (double[]) pixels; 
     965      for (int i=0; i<rtn.length; i++) { 
     966        byte[] a = new byte[] { 
     967          0, (byte) Double.doubleToLongBits(d[i*mul]), 
     968          (byte) Double.doubleToLongBits(d[i*mul + stride]), 
     969          (byte) Double.doubleToLongBits(d[i*mul + 2*stride])}; 
     970        rtn[i] = DataTools.bytesToInt(a, false); 
     971      } 
     972      d = null; 
     973    } 
     974    return rtn; 
     975  } 
     976 
    646977  // -- Image manipulation -- 
    647978 
     
    6841015        for (int i=0; i<array.length; i+=c) { 
    6851016          for (int j=0; j<c; j++) { 
    686             rtn[j][next] = array[i + j]; 
     1017            if (next < rtn[j].length) rtn[j][next] = array[i + j]; 
    6871018          } 
    6881019          next++; 
     
    7651096    if (c == 2) c = 3; // blank B channel 
    7661097 
     1098    int[] validBits = images[0].getColorModel().getComponentSize(); 
     1099    if (validBits.length < images.length) { 
     1100      int vb = validBits[0]; 
     1101      validBits = new int[c]; 
     1102      for (int i=0; i<validBits.length; i++) validBits[i] = vb; 
     1103    } 
     1104 
    7671105    // compile results into a single array 
    7681106    int w = images[0].getWidth(), h = images[0].getHeight(); 
     
    7751113      } 
    7761114      while (ndx < pix.length) pix[ndx++] = new byte[w * h]; // blank channel 
    777       return makeImage(pix, w, h); 
     1115      return makeImage(pix, w, h, validBits); 
    7781116    } 
    7791117    if (type == DataBuffer.TYPE_USHORT) { 
     
    7851123      } 
    7861124      while (ndx < pix.length) pix[ndx++] = new short[w * h]; // blank channel 
    787       return makeImage(pix, w, h); 
     1125      return makeImage(pix, w, h, validBits); 
    7881126    } 
    7891127    if (type == DataBuffer.TYPE_INT) { 
     
    7951133      } 
    7961134      while (ndx < pix.length) pix[ndx++] = new int[w * h]; // blank channel 
    797       return makeImage(pix, w, h); 
     1135      return makeImage(pix, w, h, validBits); 
    7981136    } 
    7991137    if (type == DataBuffer.TYPE_FLOAT) { 
     
    8051143      } 
    8061144      while (ndx < pix.length) pix[ndx++] = new float[w * h]; // blank channel 
    807       return makeImage(pix, w, h); 
     1145      return makeImage(pix, w, h, validBits); 
    8081146    } 
    8091147    if (type == DataBuffer.TYPE_DOUBLE) { 
     
    8151153      } 
    8161154      while (ndx < pix.length) pix[ndx++] = new double[w * h]; // blank channel 
    817       return makeImage(pix, w, h); 
     1155      return makeImage(pix, w, h, validBits); 
    8181156    } 
    8191157 
     
    8501188        byte[][] newBytes = new byte[b.length][width * height]; 
    8511189        for (int i=0; i<b.length; i++) { 
    852           newBytes[i] = padImage(b[i], img.getWidth(), width, height); 
     1190          newBytes[i] = padImage(b[i], false, 1, img.getWidth(), width, height); 
    8531191        } 
    8541192        return makeImage(newBytes, width, height); 
     
    8581196        short[][] newShorts = new short[b.length][width * height]; 
    8591197        for (int i=0; i<b.length; i++) { 
    860           newShorts[i] = padImage(b[i], img.getWidth(), width, height); 
     1198          newShorts[i] = padImage(b[i], 1, img.getWidth(), width, height); 
    8611199        } 
    8621200        return makeImage(newShorts, width, height); 
     
    8661204        int[][] newInts = new int[b.length][width * height]; 
    8671205        for (int i=0; i<b.length; i++) { 
    868           newInts[i] = padImage(b[i], img.getWidth(), width, height); 
     1206          newInts[i] = padImage(b[i], 1, img.getWidth(), width, height); 
    8691207        } 
    8701208        return makeImage(newInts, width, height); 
     
    8741212        float[][] newFloats = new float[b.length][width * height]; 
    8751213        for (int i=0; i<b.length; i++) { 
    876           newFloats[i] = padImage(b[i], img.getWidth(), width, height); 
     1214          newFloats[i] = padImage(b[i], 1, img.getWidth(), width, height); 
    8771215        } 
    8781216        return makeImage(newFloats, width, height); 
     
    8821220        double[][] newDoubles = new double[b.length][width * height]; 
    8831221        for (int i=0; i<b.length; i++) { 
    884           newDoubles[i] = padImage(b[i], img.getWidth(), width, height); 
     1222          newDoubles[i] = padImage(b[i], 1, img.getWidth(), width, height); 
    8851223        } 
    8861224        return makeImage(newDoubles, width, height); 
     
    8951233   * centered within the new bounds. 
    8961234   */ 
    897   public static byte[] padImage(byte[] b, int oldWidth, int width, int height) { 
     1235  public static byte[] padImage(byte[] b, boolean interleaved, int c, 
     1236    int oldWidth, int width, int height) 
     1237  { 
    8981238    boolean needsPadding = 
    899       (oldWidth != width) || ((b.length / oldWidth) != height); 
     1239      (oldWidth != width) || ((b.length / (oldWidth*c)) != height); 
    9001240 
    9011241    if (needsPadding) { 
     
    9091249      if (ypad == 0 && totalY > 0) ypad = totalY; 
    9101250 
    911       byte[] padded = new byte[width * height]; 
     1251      byte[] padded = new byte[width * height * c]; 
    9121252 
    9131253      int n = 0; 
     
    9191259      } 
    9201260 
     1261      if (totalX < 0) xpad = 0; 
     1262 
     1263      if (interleaved) { 
     1264        int src = 0; 
     1265        int dest = ypad * width * c + xpad * c; 
     1266 
     1267        for (int i=ypad; i<height - ypad - n; i++) { 
     1268          int len = width < oldWidth ? width * c : oldWidth * c; 
     1269          System.arraycopy(b, src, padded, dest, len); 
     1270          src += oldWidth * c; 
     1271          dest += width * c; 
     1272        } 
     1273      } 
     1274 
     1275      return padded; 
     1276    } 
     1277    return b; 
     1278  } 
     1279 
     1280  /** 
     1281   * Pad the short array to the given width and height. The image will be 
     1282   * centered within the new bounds. 
     1283   */ 
     1284  public static short[] padImage(short[] b, int c, int oldWidth, 
     1285    int width, int height) 
     1286  { 
     1287    boolean needsPadding = oldWidth != width || (b.length / oldWidth) != height; 
     1288 
     1289    if (needsPadding) { 
     1290      int totalX = width - oldWidth; 
     1291      int totalY = height - (b.length / oldWidth); 
     1292 
     1293      int xpad = totalX / 2; 
     1294      int ypad = totalY / 2; 
     1295 
     1296      if (xpad == 0 && totalX > 0) xpad = totalX; 
     1297      if (ypad == 0 && totalY > 0) ypad = totalY; 
     1298 
     1299      short[] padded = new short[width * height]; 
     1300 
     1301      int n = 0; 
     1302      if (ypad * 2 != totalY) n = 1; 
     1303 
     1304      if (totalY < 0) { 
     1305        ypad = 0; 
     1306        n = 0; 
     1307      } 
     1308 
    9211309      for (int i=ypad; i<height - ypad - n; i++) { 
    9221310        System.arraycopy(b, (i - ypad) * oldWidth, padded, i*width + xpad, 
     
    9291317 
    9301318  /** 
    931    * Pad the short array to the given width and height. The image will be 
     1319   * Pad the int array to the given width and height. The image will be 
    9321320   * centered within the new bounds. 
    9331321   */ 
    934   public static short[] padImage(short[] b, int oldWidth, int width, int height) 
     1322  public static int[] padImage(int[] b, int c, int oldWidth, 
     1323    int width, int height) 
    9351324  { 
    9361325    boolean needsPadding = oldWidth != width || (b.length / oldWidth) != height; 
     
    9461335      if (ypad == 0 && totalY > 0) ypad = totalY; 
    9471336 
    948       short[] padded = new short[width * height]; 
     1337      int[] padded = new int[width * height]; 
    9491338 
    9501339      int n = 0; 
     
    9661355 
    9671356  /** 
    968    * Pad the int array to the given width and height. The image will be 
     1357   * Pad the float array to the given width and height. The image will be 
    9691358   * centered within the new bounds. 
    9701359   */ 
    971   public static int[] padImage(int[] b, int oldWidth, int width, int height) { 
     1360  public static float[] padImage(float[] b, int c, int oldWidth, 
     1361    int width, int height) 
     1362  { 
    9721363    boolean needsPadding = oldWidth != width || (b.length / oldWidth) != height; 
    9731364 
     
    9821373      if (ypad == 0 && totalY > 0) ypad = totalY; 
    9831374 
    984       int[] padded = new int[width * height]; 
     1375      float[] padded = new float[width * height]; 
    9851376 
    9861377      int n = 0; 
     
    10021393 
    10031394  /** 
    1004    * Pad the float array to the given width and height. The image will be 
    1005    * centered within the new bounds. 
    1006    */ 
    1007   public static float[] padImage(float[] b, int oldWidth, int width, int height) 
    1008   { 
    1009     boolean needsPadding = oldWidth != width || (b.length / oldWidth) != height; 
    1010  
    1011     if (needsPadding) { 
    1012       int totalX = width - oldWidth; 
    1013       int totalY = height - (b.length / oldWidth); 
    1014  
    1015       int xpad = totalX / 2; 
    1016       int ypad = totalY / 2; 
    1017  
    1018       if (xpad == 0 && totalX > 0) xpad = totalX; 
    1019       if (ypad == 0 && totalY > 0) ypad = totalY; 
    1020  
    1021       float[] padded = new float[width * height]; 
    1022  
    1023       int n = 0; 
    1024       if (ypad * 2 != totalY) n = 1; 
    1025  
    1026       if (totalY < 0) { 
    1027         ypad = 0; 
    1028         n = 0; 
    1029       } 
    1030  
    1031       for (int i=ypad; i<height - ypad - n; i++) { 
    1032         System.arraycopy(b, (i - ypad) * oldWidth, padded, i*width + xpad, 
    1033           oldWidth); 
    1034       } 
    1035       return padded; 
    1036     } 
    1037     return b; 
    1038   } 
    1039  
    1040   /** 
    10411395   * Pad the double array to the given width and height. The image will be 
    10421396   * centered within the new bounds. 
    10431397   */ 
    1044   public static double[] padImage(double[] b, int oldWidth, int width, 
     1398  public static double[] padImage(double[] b, int c, int oldWidth, int width, 
    10451399    int height) 
    10461400  { 
     
    12651619      } 
    12661620 
    1267       return ImageTools.makeImage(out, img.getWidth(), img.getHeight()); 
     1621      return makeImage(out, img.getWidth(), img.getHeight()); 
    12681622    } 
    12691623    else if (pixels instanceof int[][]) { 
     
    12831637      } 
    12841638 
    1285       return ImageTools.makeImage(out, img.getWidth(), img.getHeight()); 
     1639      return makeImage(out, img.getWidth(), img.getHeight()); 
    12861640    } 
    12871641    else if (pixels instanceof float[][]) { 
     
    13011655      } 
    13021656 
    1303       return ImageTools.makeImage(out, img.getWidth(), img.getHeight()); 
     1657      return makeImage(out, img.getWidth(), img.getHeight()); 
    13041658    } 
    13051659    else if (pixels instanceof double[][]) { 
     
    13191673      } 
    13201674 
    1321       return ImageTools.makeImage(out, img.getWidth(), img.getHeight()); 
     1675      return makeImage(out, img.getWidth(), img.getHeight()); 
    13221676    } 
    13231677    return img; 
     
    15671921 
    15681922  /** Gets a color space for the given number of color components. */ 
    1569   public static ColorModel makeColorModel(int c, int dataType) { 
     1923  public static ColorModel makeColorModel(int c, int dataType, int[] bits) { 
    15701924    int type; 
    15711925    switch (c) { 
    15721926      case 1: 
    15731927        type = ColorSpace.CS_GRAY; 
     1928        break; 
     1929      case 2: 
     1930        type = ColorSpace.CS_sRGB; 
    15741931        break; 
    15751932      case 3: 
     
    15821939        return null; 
    15831940    } 
    1584     return new ComponentColorModel(ColorSpace.getInstance(type), 
    1585       c == 4, false, ColorModel.TRANSLUCENT, dataType); 
     1941    if (bits != null) { 
     1942      return new ComponentColorModel(ColorSpace.getInstance(type), bits, 
     1943        c == 4, false, ColorModel.TRANSLUCENT, dataType); 
     1944    } 
     1945    return new ComponentColorModel(ColorSpace.getInstance(type), c == 4, 
     1946      false, ColorModel.TRANSLUCENT, dataType); 
    15861947  } 
    15871948 
  • trunk/loci/formats/ImageViewer.java

    r1629 r1806  
    194194        if (progress.isCanceled()) break; 
    195195        img[i] = myReader.openImage(id, i); 
     196        img[i] = ImageTools.padImage(img[i], myReader.getSizeX(id), 
     197          myReader.getSizeY(id)); 
    196198        if (i == 0) setImages(id, myReader, img); 
    197199        progress.setProgress(i + 2); 
  • trunk/loci/formats/OmeisImporter.java

    r1803 r1806  
    460460    else System.err.print(msg); 
    461461  } 
    462    
     462 
    463463  /** Prints an HTTP error response header. */ 
    464464  private void printHttpErrorHeader() { 
     
    466466    System.out.print ("Content-Type: text/plain\r\n\r\n"); 
    467467  } 
    468    
     468 
    469469  /** Prints an HTTP response header. */ 
    470470  private void printHttpResponseHeader() { 
  • trunk/loci/formats/ReaderWrapper.java

    r1786 r1806  
    194194  } 
    195195 
     196  public void setNormalize(boolean normalize) { 
     197    reader.setNormalize(normalize); 
     198  } 
     199 
     200  public boolean getNormalize() { return reader.getNormalize(); } 
     201 
    196202  public void swapDimensions(String id, String order) 
    197203    throws FormatException, IOException 
  • trunk/loci/formats/TiffTools.java

    r1738 r1806  
    5151  // non-IFD tags (for internal use) 
    5252  public static final int LITTLE_ENDIAN = 0; 
     53  public static final int VALID_BITS = 1; 
    5354 
    5455  // IFD types 
     
    188189  public static final int BIG = 0x4d; 
    189190 
     191 
    190192  // -- Constructor -- 
    191193 
     
    832834 
    833835    long maxValue = getIFDLongValue(ifd, MAX_SAMPLE_VALUE, false, 0); 
     836 
     837    if (ifd.get(new Integer(VALID_BITS)) == null && bitsPerSample[0] > 0) { 
     838      int[] validBits = bitsPerSample; 
     839      if (photoInterp == RGB_PALETTE || photoInterp == CFA_ARRAY) { 
     840        int vb = validBits[0]; 
     841        validBits = new int[3]; 
     842        for (int i=0; i<validBits.length; i++) validBits[i] = vb; 
     843      } 
     844      putIFDValue(ifd, VALID_BITS, validBits); 
     845    } 
    834846 
    835847    if (ignore && (photoInterp == RGB_PALETTE || photoInterp == CFA_ARRAY)) { 
     
    13251337 
    13261338  /** Reads the image defined in the given IFD from the specified file. */ 
    1327   public static BufferedImage getImage(Hashtable ifd, RandomAccessStream in)  
     1339  public static BufferedImage getImage(Hashtable ifd, RandomAccessStream in) 
    13281340    throws FormatException, IOException 
    13291341  { 
     
    13521364    } 
    13531365 
     1366    int[] validBits = getIFDIntArray(ifd, VALID_BITS, false); 
     1367 
    13541368    if (photoInterp == RGB_PALETTE || photoInterp == CFA_ARRAY) { 
    13551369      samplesPerPixel = 3; 
     
    13681382      // Now make our image. 
    13691383      return ImageTools.makeImage(sampleData, 
    1370         (int) imageWidth, (int) imageLength); 
     1384        (int) imageWidth, (int) imageLength, validBits); 
    13711385    } 
    13721386    else if (bitsPerSample[0] == 32) { 
     
    13801394        } 
    13811395        return ImageTools.makeImage(floatData, 
    1382           (int) imageWidth, (int) imageLength); 
     1396          (int) imageWidth, (int) imageLength, validBits); 
    13831397      } 
    13841398      else { 
     
    13981412 
    13991413        return ImageTools.makeImage(shortData, 
    1400           (int) imageWidth, (int) imageLength); 
    1401       } 
    1402     } 
    1403     return ImageTools.makeImage(samples, (int) imageWidth, (int) imageLength); 
     1414          (int) imageWidth, (int) imageLength, validBits); 
     1415      } 
     1416    } 
     1417    return ImageTools.makeImage(samples, (int) imageWidth, (int) imageLength, 
     1418      validBits); 
    14041419  } 
    14051420 
  • trunk/loci/formats/in/AVIReader.java

    r1749 r1806  
    116116  /** Returns whether or not the channels are interleaved. */ 
    117117  public boolean isInterleaved(String id) throws FormatException, IOException { 
    118     return true; 
     118    return false; 
    119119  } 
    120120 
  • trunk/loci/formats/in/AndorReader.java

    r1781 r1806  
    4848  /** The dimension order of the file */ 
    4949  private String order; 
     50 
     51  /** Valid bits per pixel */ 
     52  private int[] validBits; 
    5053 
    5154  // -- Constructor -- 
     
    108111    } 
    109112    catch (Exception e) { } 
     113 
     114    int vb = 0; // number of valid bits per pixel 
    110115 
    111116    // look for MMHEADER 
     
    140145      pos++; 
    141146      String imgType; 
     147 
    142148      switch (type) { 
    143149        case 1: 
    144150          imgType = "1 bit binary"; 
     151          vb = 1; 
    145152          break; 
    146153        case 2: 
    147154          imgType = "4 bit binary"; 
     155          vb = 4; 
    148156          break; 
    149157        case 3: 
    150158          imgType = "8 bit binary"; 
     159          vb = 8; 
    151160          break; 
    152161        case 4: 
    153162          imgType = "8 bit greyscale"; 
     163          vb = 8; 
    154164          break; 
    155165        case 5: 
    156166          imgType = "12 bit greyscale"; 
     167          vb = 12; 
    157168          break; 
    158169        case 6: 
    159170          imgType = "16 bit greyscale"; 
     171          vb = 16; 
    160172          break; 
    161173        case 7: 
    162174          imgType = "32 bit greyscale"; 
     175          vb = 32; 
    163176          break; 
    164177        case 8: 
    165178          imgType = "64 bit greyscale"; 
     179          vb = 64; 
    166180          break; 
    167181        case 9: 
    168182          imgType = "24 bit color"; 
     183          vb = 8; 
    169184          break; 
    170185        case 10: 
    171186          imgType = "32 bit float"; 
     187          vb = 32; 
    172188          break; 
    173189        case 11: 
    174190          imgType = "64 bit float"; 
     191          vb = 64; 
    175192          break; 
    176193        default: 
     
    178195      } 
    179196      metadata.put("Image type", imgType); 
     197 
     198      sizeT[0] = 1; 
    180199 
    181200      for (int i=1; i<=10; i++) { 
     
    212231        // set OME-XML dimensions appropriately 
    213232 
     233        name = name.trim(); 
    214234        if (name.equals("Z")) sizeZ[series] = size; 
    215         else if (name.equals("Time")) sizeT[series] = size; 
    216         else if (!name.trim().equals("") && !name.equals("x") && 
    217           !name.equals("y")) 
     235        else if (name.equals("Time")) sizeT[series] *= size; 
     236        else if (name.equals("Wavelength")) sizeC[series] = size; 
     237        else if (!name.trim().equals("") && !name.toLowerCase().equals("x") && 
     238          !name.toLowerCase().equals("y")) 
    218239        { 
    219           sizeC[series] *= size; 
     240          sizeT[series] *= size; 
    220241        } 
    221242      } 
     
    300321 
    301322    order = "XY"; 
    302     for (int i=0; i<dimOrder.length; i++) { 
    303       String name = names[dimOrder[i]].trim(); 
    304       if (name.equals("Z") && order.indexOf("Z") < 0) order = order + "Z"; 
    305       else if (name.equals("Time") && order.indexOf("T") < 0) order=order+"T"; 
    306       else if (order.indexOf("C") < 0) order = order + "C"; 
    307     } 
    308  
    309     if (order.length() == 4) { 
    310       if (order.indexOf("Z") < 0) order = order + "Z"; 
    311       else if (order.indexOf("T") < 0) order = order + "T"; 
    312       else if (order.indexOf("C") < 0) order = order + "C"; 
    313     } 
     323    if (sizeC[0] > 1) order += "C"; 
     324    if (sizeZ[0] > sizeT[0]) order += "TZ"; 
     325    else order += "ZT"; 
     326    if (order.length() == 4) order += "C"; 
     327 
    314328    currentOrder[series] = order; 
    315329 
    316330    orderCertain[series] = true; 
     331 
     332    validBits = new int[sizeC[0]]; 
     333    if (validBits.length == 2) validBits = new int[3]; 
     334    for (int i=0; i<validBits.length; i++) validBits[i] = vb; 
     335    for (int i=0; i<ifds.length; i++) { 
     336      ifds[i].put(new Integer(TiffTools.VALID_BITS), validBits); 
     337    } 
    317338  } 
    318339 
  • trunk/loci/formats/in/BaseTiffReader.java

    r1759 r1806  
    501501        switch (bitsPerSample) { 
    502502          case 8: 
    503             pixelType[0] = FormatReader.INT8; 
     503            pixelType[0] = FormatReader.UINT8; 
    504504            break; 
    505505          case 16: 
     
    509509            pixelType[0] = FormatReader.INT32; 
    510510            break; 
     511          default: pixelType[0] = FormatReader.UINT8; 
    511512        } 
    512513      } 
     
    522523            pixelType[0] = FormatReader.UINT32; 
    523524            break; 
     525          default: pixelType[0] = FormatReader.UINT8; 
    524526        } 
    525527      } 
     
    744746    if (!id.equals(currentId)) initFile(id); 
    745747 
     748    if (no < 0 || no >= getImageCount(id)) { 
     749      throw new FormatException("Invalid image number: " + no); 
     750    } 
     751 
    746752    byte[][] p = null; 
    747753    p = TiffTools.getSamples(ifds[no], in, ignoreColorTable); 
     
    758764  { 
    759765    if (!id.equals(currentId)) initFile(id); 
     766 
     767    if (no < 0 || no >= getImageCount(id)) { 
     768      throw new FormatException("Invalid image number: " + no); 
     769    } 
     770 
    760771    int bytesPerPixel = ImageReader.getBytesPerPixel(getPixelType(id)); 
    761772    byte[] buf = new byte[getSizeX(id) * getSizeY(id) * getSizeC(id) * 
  • trunk/loci/formats/in/BioRadReader.java

    r1754 r1806  
    396396      } 
    397397    } 
    398     metadata.put("luts", colors); 
     398 
     399    String colorString = ""; 
     400    for (int i=0; i<numLuts; i++) { 
     401      for (int j=0; j<256; j++) { 
     402        for (int k=0; k<3; k++) { 
     403          colorString += (colors[i][k][j]); 
     404          if (!(j == 255 && k == 2)) colorString += ","; 
     405        } 
     406      } 
     407      colorString += "\n\n"; 
     408    } 
     409 
     410    metadata.put("luts", colorString); 
    399411 
    400412    // Populate the metadata store 
  • trunk/loci/formats/in/DeltavisionReader.java

    r1673 r1806  
    406406        imageSequence = "ZWT"; dimOrder = "XYZCT"; 
    407407        break; 
     408      case 65536: 
     409        imageSequence = "WZT"; dimOrder = "XYCZT"; 
     410        break; 
    408411      default: 
    409412        imageSequence = "unknown"; dimOrder = "XYZTC"; 
  • trunk/loci/formats/in/FluoviewReader.java

    r1759 r1806  
    376376      } 
    377377 
     378      // set the number of valid bits per pixel 
     379 
     380      String bits = (String) metadata.get("Map Ch" + (sizeC[0] - 1) + ": Range"); 
     381      int[] validBits = null; 
     382      int vb = -1; 
     383      if (bits != null && bits.length() > 0) { 
     384        int start = Integer.parseInt(bits.substring(0, bits.indexOf(" to"))); 
     385        int end = Integer.parseInt(bits.substring(bits.indexOf("to") + 3)); 
     386        while (Math.pow(2, vb) < end) vb++; 
     387      } 
     388 
     389      if (vb > -1) { 
     390        validBits = new int[sizeC[0]]; 
     391        if (validBits.length == 2) validBits = new int[3]; 
     392        for (int i=0; i<validBits.length; i++) validBits[i] = vb; 
     393      } 
     394 
     395      for (int i=0; i<ifds.length; i++) { 
     396        ifds[i].put(new Integer(TiffTools.VALID_BITS), validBits); 
     397      } 
     398 
    378399      if (setZ && !setT) sizeT[series] = 1; 
    379400      if (setT && !setZ) sizeZ[series] = 1; 
  • trunk/loci/formats/in/ICSReader.java

    r1718 r1806  
    9797  public int getImageCount(String id) throws FormatException, IOException { 
    9898    if (!id.equals(currentIdsId) && !id.equals(currentIcsId)) initFile(id); 
    99     return numImages / (rgb ? 3 : 1); 
     99    if (numImages == 1) return 1; 
     100    return numImages / (isRGB(id) ? 3 : 1); 
    100101  } 
    101102 
     
    109110  public boolean isLittleEndian(String id) throws FormatException, IOException { 
    110111    if (!id.equals(currentIdsId) && !id.equals(currentIcsId)) initFile(id); 
    111     return !littleEndian; 
     112    return littleEndian; 
    112113  } 
    113114 
     
    143144      return t; 
    144145    } 
     146 
    145147    return plane; 
    146148  } 
     
    155157    int width = dimensions[1]; 
    156158    int height = dimensions[2]; 
    157     int channels = rgb ? 3 : 1; 
    158  
    159     if (dimensions[0] == 32) { 
    160       // Some justification for this approach: 
    161       // Java won't allow us to create a grayscale BufferedImage with float 
    162       // data.  We could (theoretically) display all floating point data as 
    163       // RGB, effectively tripling the amount of memory needed.  However, tests 
    164       // showed that the images produced using float + RGB were worse than 
    165       // those produced by the following method.  So, yes this wrong, and yes 
    166       // it will result in some data loss.  Feel free to change this if you 
    167       // have any better ideas (just remember to update the pixel type as well). 
    168       short[][] f = new short[channels][plane.length / 4]; 
    169       int p = 0; 
    170       for (int j=0; j<f[0].length; j++) { 
    171         for (int i=0; i<f.length; i++) { 
    172           f[i][j] = (short) Float.intBitsToFloat(DataTools.bytesToInt(plane, 
    173             p*4, 4, littleEndian)); 
    174           p++; 
    175         } 
    176       } 
    177       return ImageTools.makeImage(f, width, height); 
    178     } 
    179     else return ImageTools.makeImage(plane, width, height, channels, false, 
    180       dimensions[0] / 8, !littleEndian); 
     159    int channels = isRGB(id) ? 3 : 1; 
     160 
     161    int bytes = dimensions[0] / 8; 
     162 
     163    if (bytes == 4) { 
     164      float[] f = new float[width * height * channels]; 
     165      int pt = 0; 
     166      for (int i=0; i<f.length; i++) { 
     167        int p = DataTools.bytesToInt(plane, i*4, 4, littleEndian); 
     168        f[i] = Float.intBitsToFloat(p); 
     169      } 
     170 
     171      if (normalizeData) f = DataTools.normalizeFloats(f); 
     172 
     173      return ImageTools.makeImage(f, width, height, channels, true); 
     174    } 
     175 
     176    return ImageTools.makeImage(plane, width, height, channels, true, 
     177      bytes, !littleEndian); 
    181178  } 
    182179 
     
    191188  } 
    192189 
    193   /** Initializes the given IPLab file. */ 
     190  /** Initializes the given ICS file. */ 
    194191  protected void initFile(String id) throws FormatException, IOException { 
    195192    super.initFile(id); 
     
    309306 
    310307    numImages = dimensions[3] * dimensions[4] * dimensions[5]; 
     308    if (numImages == 0) numImages++; 
    311309 
    312310    String endian = (String) metadata.get("byte_order"); 
     
    387385    String sign = (String) metadata.get("sign"); 
    388386 
    389     if (fmt.equals("real")) pixelType[0] = FormatReader.UINT16; 
     387    if (fmt.equals("real")) pixelType[0] = FormatReader.FLOAT; 
    390388    else if (fmt.equals("integer")) { 
    391389      while (bitsPerPixel % 8 != 0) bitsPerPixel++; 
  • trunk/loci/formats/in/IPLabReader.java

    r1673 r1806  
    107107  /** Returns whether or not the channels are interleaved. */ 
    108108  public boolean isInterleaved(String id) throws FormatException, IOException { 
    109     return false; 
     109    return true; 
    110110  } 
    111111 
  • trunk/loci/formats/in/IPWReader.java

    r1755 r1806  
    347347    while (bitsPerSample % 8 != 0) bitsPerSample++; 
    348348    if (bitsPerSample == 24 || bitsPerSample == 48) bitsPerSample /= 3; 
     349 
     350    pixelType[0] = FormatReader.UINT8; 
    349351 
    350352    if (bitFormat == 3) pixelType[0] = FormatReader.FLOAT; 
  • trunk/loci/formats/in/ImageIOReader.java

    r1673 r1806  
    7373  /** Returns whether or not the channels are interleaved. */ 
    7474  public boolean isInterleaved(String id) throws FormatException, IOException { 
    75     return false; 
     75    return true; 
    7676  } 
    7777 
     
    113113    MetadataStore store = getMetadataStore(id); 
    114114 
    115     pixelType[0] = FormatReader.INT8; 
     115    pixelType[0] = FormatReader.UINT8; 
    116116    store.setPixels( 
    117117      new Integer(getSizeX(id)), 
  • trunk/loci/formats/in/LIFReader.java

    r1750 r1806  
    6565  protected int[][] dims; 
    6666 
     67  /** Number of valid bits per pixel */ 
     68  private int[][] validBits; 
     69 
    6770  private int width; 
    6871  private int height; 
     
    153156    height = dims[series][1]; 
    154157    c = dims[series][4]; 
    155     if (c == 2) c--; 
     158    //if (c == 2) c--; 
    156159    bpp = dims[series][5]; 
    157160    while (bpp % 8 != 0) bpp++; 
     
    174177  { 
    175178    return ImageTools.makeImage(openBytes(id, no), width, height, 
    176       !isRGB(id) ? 1 : c, false, bpp / 8, littleEndian); 
     179      !isRGB(id) ? 1 : c, false, bpp / 8, littleEndian, validBits[series]); 
    177180  } 
    178181 
     
    427430        } 
    428431        extraDims.add(new Integer(extras)); 
    429         if (numChannels == 2) numChannels--; 
     432        //if (numChannels == 2) numChannels--; 
    430433        if (numChannels == 0) numChannels++; 
    431434        channels.add(new Integer(numChannels)); 
     
    481484    Arrays.fill(orderCertain, true); 
    482485 
     486    validBits = new int[numDatasets][1]; 
     487 
    483488    for (int i=0; i<numDatasets; i++) { 
    484489      sizeX[i] = dims[i][0]; 
     
    488493      sizeT[i] = dims[i][3]; 
    489494      currentOrder[i] = (sizeZ[i] > sizeT[i]) ? "XYCZT" : "XYCTZ"; 
     495 
     496      validBits[i] = new int[sizeC[i] != 2 ? sizeC[i] : 3]; 
     497      for (int j=0; j<validBits[i].length; j++) { 
     498        validBits[i][j] = dims[i][5]; 
     499      } 
    490500 
    491501      while (dims[i][5] % 8 != 0) dims[i][5]++; 
  • trunk/loci/formats/in/LeicaReader.java

    r1781 r1806  
    7373  /** Total number of planes in each series. */ 
    7474  private int[] numPlanes; 
     75 
     76  /** Number of significant bits per pixel. */ 
     77  private int[][] validBits; 
    7578 
    7679  // -- Constructor -- 
     
    180183    BufferedImage b = 
    181184      tiff[series][no].openImage((String) files[series].get(no), 0); 
     185    b = ImageTools.makeBuffered(b, 
     186      ImageTools.makeColorModel(b.getRaster().getNumBands(), 
     187      b.getRaster().getTransferType(), validBits[series])); 
    182188    tiff[series][no].close(); 
    183189    return b; 
     
    803809      // BaseTiffReader.initMetadata 
    804810    } 
     811 
     812    Integer v = (Integer) metadata.get("Real world resolution"); 
     813 
     814    if (v != null) { 
     815      validBits = new int[sizeC.length][]; 
     816 
     817      for (int i=0; i<validBits.length; i++) { 
     818        validBits[i] = new int[sizeC[i]]; 
     819        for (int j=0; j<validBits[i].length; j++) { 
     820          validBits[i][j] = v.intValue(); 
     821        } 
     822      } 
     823    } 
     824    else validBits = null; 
    805825 
    806826    // The metadata store we're working with. 
     
    860880      catch (NullPointerException n) { } 
    861881    } 
     882 
    862883  } 
    863884 
  • trunk/loci/formats/in/MetamorphReader.java

    r1759 r1806  
    130130              StringBuffer sb = new StringBuffer(); 
    131131              char c = (char) in.read(); 
    132               while (c != 0) { 
     132              while (c != 0 || sb.length() < 256) { 
    133133                sb = sb.append(c); 
    134134                c = (char) in.read(); 
  • trunk/loci/formats/in/ND2Reader.java

    r1785 r1806  
    2626 
    2727import java.awt.Image; 
    28 import java.awt.image.BufferedImage; 
     28import java.awt.image.*; 
    2929import java.io.*; 
    3030import java.util.StringTokenizer; 
     
    7878  private long[] offsets; 
    7979 
     80  /** Number of valid bits per pixel */ 
     81  private int[] validBits; 
     82 
    8083  // -- Constructor -- 
    8184 
     
    223226 
    224227      Image img = (Image) r.getVar("img"); 
     228 
     229      int dataType = 0; 
     230      switch (pixelType[0]) { 
     231        case FormatReader.INT8: 
     232        case FormatReader.UINT8: dataType = DataBuffer.TYPE_BYTE; break; 
     233        case FormatReader.INT16: 
     234        case FormatReader.UINT16: dataType = DataBuffer.TYPE_USHORT; break; 
     235        case FormatReader.INT32: 
     236        case FormatReader.UINT32: dataType = DataBuffer.TYPE_INT; break; 
     237        case FormatReader.FLOAT: dataType = DataBuffer.TYPE_FLOAT; break; 
     238        case FormatReader.DOUBLE: dataType = DataBuffer.TYPE_DOUBLE; break; 
     239      } 
     240 
     241      ColorModel cm = ImageTools.makeColorModel(sizeC[0], dataType, validBits); 
    225242      return ImageTools.makeBuffered(img); 
    226243    } 
     
    312329      ras.read(b); 
    313330      String xml = new String(b); 
    314      
     331 
    315332      // assume that this XML string will be malformed, since that's how both 
    316333      // sample files are; this means we need to manually parse it :-( 
     
    328345      // strip out binary data at the end - this is irrelevant for our purposes 
    329346      xml = xml.substring(0, xml.lastIndexOf("</MetadataSeq>") + 14); 
    330     
     347 
    331348      // each chunk appears on a separate line, so split up the chunks 
    332349 
     
    352369                int eq = s.indexOf("="); 
    353370                String key = s.substring(0, eq).trim(); 
    354                 String value =  
     371                String value = 
    355372                  s.substring(eq + 2, s.indexOf("\"", eq + 2)).trim(); 
    356                  
     373 
    357374                // strip out the data types 
    358375                if (key.indexOf("runtype") == -1) { 
     
    367384    } 
    368385 
    369     // TODO : use sigBits to compute pixel type 
    370     String sigBits =  
     386    String sigBits = 
    371387      (String) metadata.get("AdvancedImageAttributes SignificantBits value"); 
    372388    int bits = 0; 
     
    391407    } 
    392408 
    393     String channels =  
     409    String channels = 
    394410      (String) metadata.get("AdvancedImageAttributes VirtualComponents value"); 
    395411    if (channels != null && channels.length() > 0) { 
     
    403419    currentOrder[0] = sizeC[0] == 3 ? "XYCTZ" : "XYTZC"; 
    404420    pixelType[0] = ImageTools.getPixelType(img); 
     421 
     422    if (bits != 0) { 
     423      validBits = new int[sizeC[0]]; 
     424      for (int i=0; i<validBits.length; i++) validBits[i] = bits; 
     425    } 
     426    else validBits = null; 
    405427 
    406428    MetadataStore store = getMetadataStore(id); 
     
    415437      currentOrder[0], 
    416438      null); 
    417    
     439 
    418440    store.setDimensions(new Float(pixSizeX), new Float(pixSizeX), 
    419441      new Float(pixSizeZ), null, null, null); 
    420    
     442 
    421443  } 
    422444 
  • trunk/loci/formats/in/NikonReader.java

    r1759 r1806  
    214214 
    215215    Hashtable realImage = TiffTools.getIFD(in, 1, offset); 
     216    realImage.put(new Integer(TiffTools.VALID_BITS), new int[] {12, 12, 12}); 
    216217 
    217218    original = ifds[0]; 
  • trunk/loci/formats/in/OIFReader.java

    r1718 r1806  
    176176      File.separator; 
    177177 
    178     if (id.indexOf("_") != -1) { 
    179       thumbId = dir + id.substring(id.lastIndexOf(File.separator) + 1, 
    180         id.lastIndexOf("_") + 1) + "Thumb.bmp"; 
    181     } 
    182     else { 
    183       thumbId = dir + id.substring(id.lastIndexOf(File.separator) + 1, 
    184         id.lastIndexOf(".")) + "_Thumb.bmp"; 
    185     } 
     178    thumbId = dir + id.substring(id.lastIndexOf(File.separator) + 1, 
     179      id.lastIndexOf(".")) + "_Thumb.bmp"; 
    186180    thumbReader.setIgnoreColorTable(ignoreColorTable); 
    187181    return thumbReader.openImage(thumbId, 0); 
  • trunk/loci/formats/in/OMEXMLReader.java

    r1750 r1806  
    358358      if (type.endsWith("16")) { 
    359359        bpp[i] = 2; 
    360         pixelType[i] = type.indexOf("u") == -1 ? FormatReader.INT16 : 
    361           FormatReader.UINT16; 
     360        pixelType[i] = FormatReader.UINT16; 
    362361      } 
    363362      else if (type.endsWith("32")) { 
    364363        bpp[i] = 4; 
    365         pixelType[i] = type.indexOf("u") == -1 ? FormatReader.INT32 : 
    366           FormatReader.UINT32; 
     364        pixelType[i] = FormatReader.UINT32; 
    367365      } 
    368366      else if (type.equals("float")) { 
     
    372370      else { 
    373371        bpp[i] = 1; 
    374         pixelType[i] = type.indexOf("u") == -1 ? FormatReader.INT8 : 
    375           FormatReader.UINT8; 
     372        pixelType[i] = FormatReader.UINT8; 
    376373      } 
    377374 
  • trunk/loci/formats/in/PerkinElmerReader.java

    r1673 r1806  
    493493    } 
    494494 
    495     currentOrder[0] = "XY"; 
     495    currentOrder[0] = "XYC"; 
    496496 
    497497    if (sizeZ[0] <= 0) { 
     
    505505    if (sizeT[0] <= 0) sizeT[0] = 1; 
    506506 
    507     int[] sizes = {sizeZ[0], sizeC[0], sizeT[0]}; 
    508  
    509     int largest = 0; 
    510     int largestIndex = 0; 
    511     int smallest = Integer.MAX_VALUE; 
    512     int smallestIndex = 0; 
    513     for (int i=0; i<sizes.length; i++) { 
    514       if (sizes[i] > largest) { 
    515         largest = sizes[i]; 
    516         largestIndex = i; 
    517       } 
    518       else if (sizes[i] < smallest) { 
    519         smallest = sizes[i]; 
    520         smallestIndex = i; 
    521       } 
    522     } 
    523  
    524     String[] names = {"Z", "C", "T"}; 
    525     currentOrder[0] += names[largestIndex]; 
    526     for (int i=0; i<names.length; i++) { 
    527       if (i != largestIndex && i != smallestIndex) { 
    528         currentOrder[0] += names[i]; 
    529         break; 
    530       } 
    531     } 
    532     currentOrder[0] += names[smallestIndex]; 
     507    if (sizeZ[0] < sizeT[0]) currentOrder[0] += "ZT"; 
     508    else currentOrder[0] += "TZ"; 
    533509 
    534510    // Populate metadata store 
  • trunk/loci/formats/in/ZeissZVIReader.java

    r1755 r1806  
    117117  private Vector tIndices; 
    118118 
     119  /** Valid bits per pixel */ 
     120  private int[] validBits; 
     121 
    119122  private Hashtable offsets; 
    120123 
     
    208211  /** Returns whether or not the channels are interleaved. */ 
    209212  public boolean isInterleaved(String id) throws FormatException, IOException { 
    210     return true; 
     213    return false; 
    211214  } 
    212215 
     
    295298 
    296299    return ImageTools.makeImage(openBytes(id, no), width, height, 
    297       isRGB(id) ? 3 : 1, true, bpp == 3 ? 1 : bpp, true); 
     300      isRGB(id) ? 3 : 1, true, bpp == 3 ? 1 : bpp, true, validBits); 
    298301  } 
    299302 
     
    372375      sizeC[0] = nChannels; 
    373376      sizeT[0] = tSize; 
     377 
     378      String s = (String) metadata.get("Acquisition Bit Depth"); 
     379      if (s != null && s.trim().length() > 0) { 
     380        validBits = new int[nChannels]; 
     381        if (nChannels == 2) validBits = new int[3]; 
     382        for (int i=0; i<nChannels; i++) { 
     383          validBits[i] = Integer.parseInt(s.trim()); 
     384        } 
     385      } 
     386      else validBits = null; 
    374387 
    375388      Object check = metadata.get("Image Channel Index"); 
  • trunk/loci/formats/readers.txt

    r1777 r1806  
    3232loci.formats.in.IPLabReader       # ipl 
    3333loci.formats.in.DeltavisionReader # dv, r3d 
     34loci.formats.in.MRCReader         # mrc 
    3435loci.formats.in.GatanReader       # dm3 
    3536loci.formats.in.ImarisReader      # ims 
Note: See TracChangeset for help on using the changeset viewer.