Changeset 7573


Ignore:
Timestamp:
01/21/11 21:26:27 (9 years ago)
Author:
melissa
Message:

Backported a bunch of recent ND2 fixes to 4.1.

Location:
branches/4.1/components/bio-formats/src/loci/formats
Files:
3 edited
1 copied

Legend:

Unmodified
Added
Removed
  • branches/4.1/components/bio-formats/src/loci/formats/FormatReader.java

    r7447 r7573  
    317317    int w, int h, byte[] buf) throws IOException 
    318318  { 
     319    return readPlane(s, x, y, w, h, 0, buf); 
     320  } 
     321 
     322  /** Reads a raw plane from disk. */ 
     323  protected byte[] readPlane(RandomAccessInputStream s, int x, int y, 
     324    int w, int h, int scanlinePad, byte[] buf) throws IOException 
     325  { 
    319326    int c = getRGBChannelCount(); 
    320327    int bpp = FormatTools.getBytesPerPixel(getPixelType()); 
    321     if (x == 0 && y == 0 && w == getSizeX() && h == getSizeY()) { 
     328    if (x == 0 && y == 0 && w == getSizeX() && h == getSizeY() && 
     329      scanlinePad == 0) 
     330    { 
    322331      s.read(buf); 
    323332    } 
    324     else if (x == 0 && w == getSizeX()) { 
     333    else if (x == 0 && w == getSizeX() && scanlinePad == 0) { 
    325334      if (isInterleaved()) { 
    326335        s.skipBytes(y * w * bpp * c); 
     
    337346    } 
    338347    else { 
     348      int scanlineWidth = getSizeX() + scanlinePad; 
    339349      if (isInterleaved()) { 
    340         s.skipBytes(y * getSizeX() * bpp * c); 
     350        s.skipBytes(y * scanlineWidth * bpp * c); 
    341351        for (int row=0; row<h; row++) { 
    342352          s.skipBytes(x * bpp * c); 
    343353          s.read(buf, row * w * bpp * c, w * bpp * c); 
    344           s.skipBytes(bpp * c * (getSizeX() - w - x)); 
     354          s.skipBytes(bpp * c * (scanlineWidth - w - x)); 
    345355        } 
    346356      } 
    347357      else { 
    348358        for (int channel=0; channel<c; channel++) { 
    349           s.skipBytes(y * getSizeX() * bpp); 
     359          s.skipBytes(y * scanlineWidth * bpp); 
    350360          for (int row=0; row<h; row++) { 
    351361            s.skipBytes(x * bpp); 
    352362            s.read(buf, channel * w * h * bpp + row * w * bpp, w * bpp); 
    353             s.skipBytes(bpp * (getSizeX() - w - x)); 
     363            s.skipBytes(bpp * (scanlineWidth - w - x)); 
    354364          } 
    355           s.skipBytes(getSizeX() * bpp * (getSizeY() - y - h)); 
     365          s.skipBytes(scanlineWidth * bpp * (getSizeY() - y - h)); 
    356366        } 
    357       } 
     367     } 
    358368    } 
    359369    return buf; 
  • branches/4.1/components/bio-formats/src/loci/formats/in

  • branches/4.1/components/bio-formats/src/loci/formats/in/ND2Handler.java

    r6819 r7573  
    2828import java.util.Hashtable; 
    2929 
     30import loci.common.DateTools; 
    3031import loci.formats.CoreMetadata; 
    3132import loci.formats.FormatException; 
    3233import loci.formats.FormatTools; 
     34import loci.formats.MetadataTools; 
     35import loci.formats.meta.MetadataStore; 
    3336 
    3437import org.xml.sax.Attributes; 
     
    4346 */ 
    4447public class ND2Handler extends DefaultHandler { 
     48 
     49  // -- Constants -- 
     50 
     51  private static final String DATE_FORMAT = "dd/MM/yyyy  HH:mm:ss"; 
    4552 
    4653  // -- Fields -- 
     
    8188  private String cameraModel; 
    8289  private int fieldIndex = 0; 
     90  private String date; 
     91 
     92  private Hashtable<String, Integer> colors = new Hashtable<String, Integer>(); 
     93  private Hashtable<String, String> dyes = new Hashtable<String, String>(); 
     94  private Hashtable<String, Integer> realColors = 
     95    new Hashtable<String, Integer>(); 
    8396 
    8497  // -- Constructor -- 
     
    91104  // -- ND2Handler API methods -- 
    92105 
     106  public CoreMetadata[] getCoreMetadata() { 
     107    return core; 
     108  } 
     109 
     110  public void populateROIs(MetadataStore store) { 
     111    for (int r=0; r<rois.size(); r++) { 
     112      Hashtable<String, String> roi = rois.get(r); 
     113      String type = roi.get("ROIType"); 
     114 
     115      if (type.equals("Text")) { 
     116        store.setROIID(MetadataTools.createLSID("ROI", 0, r), 0, r); 
     117 
     118        String rectangle = roi.get("rectangle"); 
     119        String[] p = rectangle.split(","); 
     120        double[] points = new double[p.length]; 
     121        for (int i=0; i<p.length; i++) { 
     122          points[i] = Double.parseDouble(p[i]); 
     123        } 
     124 
     125        store.setRectID(MetadataTools.createLSID("Shape", 0, r, 1), 0, r, 1); 
     126        store.setRectX(p[0], 0, r, 1); 
     127        store.setRectY(p[1], 0, r, 1); 
     128        store.setRectWidth(String.valueOf(points[2] - points[0]), 0, r, 1); 
     129        store.setRectHeight(String.valueOf(points[3] - points[1]), 0, r, 1); 
     130      } 
     131      else if (type.equals("HorizontalLine") || type.equals("VerticalLine")) { 
     132        store.setROIID(MetadataTools.createLSID("ROI", 0, r), 0, r); 
     133 
     134        String segments = roi.get("segments"); 
     135        segments = segments.replaceAll("\\[\\]", ""); 
     136        String[] points = segments.split("\\)"); 
     137 
     138        StringBuffer sb = new StringBuffer(); 
     139        for (int i=0; i<points.length; i++) { 
     140          points[i] = points[i].substring(points[i].indexOf(":") + 1); 
     141          sb.append(points[i]); 
     142          if (i < points.length - 1) sb.append(" "); 
     143        } 
     144 
     145        store.setPolylineID( 
     146          MetadataTools.createLSID("Shape", 0, r, 0), 0, r, 0); 
     147        store.setPolylinePoints(sb.toString(), 0, r, 0); 
     148      } 
     149    } 
     150  } 
     151 
     152  public String getDate() { 
     153    return date; 
     154  } 
     155 
    93156  public Hashtable<String, Object> getMetadata() { 
    94157    return metadata; 
     
    217280  public int getFieldIndex() { 
    218281    return fieldIndex; 
     282  } 
     283 
     284  public Hashtable<String, Integer> getChannelColors() { 
     285    return realColors; 
    219286  } 
    220287 
     
    247314      int bytes = Integer.parseInt(value) / div; 
    248315 
    249       try { 
    250         core[0].pixelType = 
    251           FormatTools.pixelTypeFromBytes(bytes, false, false); 
    252       } 
    253       catch (FormatException e) { } 
     316      switch (bytes) { 
     317        case 1: 
     318          core[0].pixelType = FormatTools.UINT8; 
     319          break; 
     320        case 2: 
     321          core[0].pixelType = FormatTools.UINT16; 
     322          break; 
     323        case 4: 
     324          core[0].pixelType = FormatTools.UINT32; 
     325          break; 
     326      } 
    254327      parseKeyAndValue(qName, value, prevRuntype); 
    255328    } 
    256329    else if ("dPosX".equals(prevElement) && qName.startsWith("item_")) { 
    257330      posX.add(new Double(sanitizeDouble(value))); 
     331      metadata.put("X position for position #" + posX.size(), value); 
    258332    } 
    259333    else if ("dPosY".equals(prevElement) && qName.startsWith("item_")) { 
    260334      posY.add(new Double(sanitizeDouble(value))); 
     335      metadata.put("Y position for position #" + posY.size(), value); 
    261336    } 
    262337    else if ("dPosZ".equals(prevElement) && qName.startsWith("item_")) { 
    263338      posZ.add(new Double(sanitizeDouble(value))); 
     339      metadata.put("Z position for position #" + posZ.size(), value); 
    264340    } 
    265341    else if (qName.startsWith("item_")) { 
     
    268344        fieldIndex = core[0].dimensionOrder.length(); 
    269345        numSeries++; 
     346      } 
     347      else if (v < numSeries && fieldIndex < core[0].dimensionOrder.length()) { 
     348        fieldIndex = core[0].dimensionOrder.length(); 
    270349      } 
    271350    } 
     
    302381      metadata.put("Pinhole size", value); 
    303382    } 
     383    else if (qName.endsWith("ChannelColor")) { 
     384      String name = qName.substring(0, qName.indexOf("Channel")); 
     385      colors.put(name, new Integer(value)); 
     386    } 
     387    else if (qName.endsWith("DyeName")) { 
     388      int channelIndex = qName.indexOf("Channel"); 
     389      if (channelIndex < 0) channelIndex = 0; 
     390      dyes.put(qName.substring(0, channelIndex), value); 
     391    } 
     392    else if (qName.equals("uiSequenceCount")) { 
     393      int imageCount = Integer.parseInt(value); 
     394      if (core.length > 0) imageCount /= core.length; 
     395      if (core[0].sizeZ * core[0].sizeT != imageCount && 
     396        core[0].sizeZ * core[0].sizeC * core[0].sizeT != imageCount) 
     397      { 
     398        if (core[0].sizeZ > 1) { 
     399          core[0].sizeZ = imageCount; 
     400          core[0].sizeT = 1; 
     401        } 
     402        else if (core[0].sizeT > 1) { 
     403          core[0].sizeT = imageCount; 
     404          core[0].sizeZ = 1; 
     405        } 
     406        core[0].imageCount = imageCount; 
     407      } 
     408      metadata.put(qName, value); 
     409    } 
    304410    else { 
    305411      StringBuffer sb = new StringBuffer(); 
     
    313419 
    314420    prevRuntype = attributes.getValue("runtype"); 
     421  } 
     422 
     423  public void endDocument() { 
     424    for (String name : colors.keySet()) { 
     425      String chName = dyes.get(name); 
     426      if (chName == null) chName = name; 
     427      realColors.put(chName, colors.get(name)); 
     428    } 
    315429  } 
    316430 
     
    327441      pixelSizeZ = Double.parseDouble(sanitizeDouble(value)); 
    328442    } 
    329     else if (key.endsWith("Gain")) gain.add(new Double(sanitizeDouble(value))); 
     443    else if (key.endsWith("Gain")) { 
     444      value = sanitizeDouble(value); 
     445      if (!value.equals("")) { 
     446        gain.add(new Double(value)); 
     447      } 
     448    } 
    330449    else if (key.endsWith("dLampVoltage")) { 
    331450      voltage = new Double(sanitizeDouble(value)); 
     
    340459      refractiveIndex = new Double(sanitizeDouble(value)); 
    341460    } 
    342     else if (key.equals("sObjective") || key.equals("wsObjectiveName")) { 
     461    else if (key.equals("sObjective") || key.equals("wsObjectiveName") || 
     462      key.equals("sOptics")) 
     463    { 
    343464      String[] tokens = value.split(" "); 
    344465      int magIndex = -1; 
     
    356477      if (magIndex >= 0) { 
    357478        String m = tokens[magIndex].substring(0, tokens[magIndex].indexOf("x")); 
    358         mag = new Double(sanitizeDouble(m)); 
     479        m = sanitizeDouble(m); 
     480        if (m.length() > 0) { 
     481          mag = new Double(m); 
     482        } 
    359483      } 
    360484      if (magIndex + 1 < tokens.length) immersion = tokens[magIndex + 1]; 
     
    392516        } 
    393517      } 
    394     } 
    395     else if (key.endsWith("uiBpcSignificant")) { 
    396       core[0].bitsPerPixel = Integer.parseInt(value); 
    397518    } 
    398519    else if (key.equals("VirtualComponents")) { 
     
    537658      } 
    538659    } 
     660    else if (key.equals("CameraUniqueName")) { 
     661      cameraModel = value; 
     662    } 
     663    else if (key.equals("ExposureTime")) { 
     664      exposureTime.add(new Double(value) / 1000d); 
     665    } 
     666    else if (key.equals("sDate")) { 
     667      date = DateTools.formatDate(value, DATE_FORMAT); 
     668    } 
    539669  } 
    540670 
  • branches/4.1/components/bio-formats/src/loci/formats/in/NativeND2Reader.java

    r5826 r7573  
    2525 
    2626import java.io.IOException; 
    27 import java.text.DecimalFormatSymbols; 
     27import java.util.ArrayList; 
    2828import java.util.Hashtable; 
    29 import java.util.StringTokenizer; 
    30 import java.util.Vector; 
    31  
     29 
     30import loci.common.ByteArrayHandle; 
    3231import loci.common.Location; 
    3332import loci.common.RandomAccessInputStream; 
     
    3736import loci.formats.FormatReader; 
    3837import loci.formats.FormatTools; 
     38import loci.formats.ImageTools; 
    3939import loci.formats.MetadataTools; 
    40 import loci.formats.codec.ByteVector; 
     40import loci.formats.codec.Codec; 
    4141import loci.formats.codec.CodecOptions; 
    4242import loci.formats.codec.JPEG2000Codec; 
     
    4444import loci.formats.meta.FilterMetadata; 
    4545import loci.formats.meta.MetadataStore; 
    46  
    47 import org.xml.sax.Attributes; 
    48 import org.xml.sax.helpers.DefaultHandler; 
    4946 
    5047/** 
     
    5956 * 
    6057 * <dl><dt><b>Source code:</b></dt> 
    61  * <dd><a href="https://skyking.microscopy.wisc.edu/trac/java/browser/trunk/components/bio-formats/src/loci/formats/in/NativeND2Reader.java">Trac</a>, 
    62  * <a href="https://skyking.microscopy.wisc.edu/svn/java/trunk/components/bio-formats/src/loci/formats/in/NativeND2Reader.java">SVN</a></dd></dl> 
     58 * <dd><a href="http://dev.loci.wisc.edu/trac/java/browser/trunk/components/bio-formats/src/loci/formats/in/NativeND2Reader.java">Trac</a>, 
     59 * <a href="http://dev.loci.wisc.edu/svn/java/trunk/components/bio-formats/src/loci/formats/in/NativeND2Reader.java">SVN</a></dd></dl> 
    6360 */ 
    6461public class NativeND2Reader extends FormatReader { 
     
    7774  private boolean isJPEG; 
    7875 
     76  /** Codec to use when decompressing pixel data. */ 
     77  private Codec codec; 
     78 
    7979  /** Whether or not the pixel data is losslessly compressed. */ 
    8080  private boolean isLossless; 
    8181 
    82   private Vector<Long> zs = new Vector<Long>(); 
    83   private Vector<Long> ts = new Vector<Long>(); 
    84   private Vector<Float> tsT = new Vector<Float>(); 
    85  
    86   private int numSeries; 
    87  
    88   private float pixelSizeX, pixelSizeY, pixelSizeZ; 
    89   private Float pinholeSize; 
    90   private String voltage, mag, na, objectiveModel, immersion, correction; 
    91  
    92   private Vector<String> channelNames, modality, binning; 
    93   private Vector<Float> speed, gain, temperature, exposureTime; 
    94   private Vector<Integer> exWave, emWave, power; 
    95   private Vector<Hashtable<String, String>> rois; 
    96   private Vector<Float> posX, posY, posZ; 
    97  
    98   private String cameraModel; 
     82  private ArrayList<Double> tsT = new ArrayList<Double>(); 
    9983 
    10084  private int fieldIndex; 
     85 
     86  private long xOffset, yOffset, zOffset; 
     87 
     88  private ArrayList<Double> posX; 
     89  private ArrayList<Double> posY; 
     90  private ArrayList<Double> posZ; 
     91 
     92  private Hashtable<String, Integer> channelColors; 
     93  private boolean split = false; 
     94  private int lastChannel; 
     95  private int[] colors; 
    10196 
    10297  // -- Constructor -- 
     
    120115  } 
    121116 
     117  /* @see loci.formats.IFormatReader#get8BitLookupTable() */ 
     118  public byte[][] get8BitLookupTable() { 
     119    if (FormatTools.getBytesPerPixel(getPixelType()) != 1 || 
     120      !isIndexed() || lastChannel < 0 || lastChannel >= colors.length) 
     121    { 
     122      return null; 
     123    } 
     124 
     125    int color = colors[lastChannel]; 
     126    byte[][] lut = new byte[3][256]; 
     127 
     128    int index = -1; 
     129    if (color > 0 && color < 256) index = 0; 
     130    else if (color >= 256 && color < 65280) index = 1; 
     131    else if (color > 65280 && color <= 16711680) index = 2; 
     132 
     133    for (int i=0; i<256; i++) { 
     134      if (index == -1) { 
     135        lut[0][i] = (byte) i; 
     136        lut[1][i] = (byte) i; 
     137        lut[2][i] = (byte) i; 
     138      } 
     139      else { 
     140        lut[index][i] = (byte) i; 
     141      } 
     142    } 
     143 
     144    return lut; 
     145  } 
     146 
     147  /* @see loci.formats.IFormatReader#get16BitLookupTable() */ 
     148  public short[][] get16BitLookupTable() { 
     149    if (FormatTools.getBytesPerPixel(getPixelType()) != 2 || 
     150      !isIndexed() || lastChannel < 0 || lastChannel >= colors.length) 
     151    { 
     152      return null; 
     153    } 
     154 
     155    int color = colors[lastChannel]; 
     156    short[][] lut = new short[3][65536]; 
     157 
     158    int index = -1; 
     159    if (color > 0 && color < 256) index = 0; 
     160    else if (color >= 256 && color <= 65280) index = 1; 
     161    else if (color > 65280 && color <= 16711680) index = 2; 
     162 
     163    for (int i=0; i<65536; i++) { 
     164      if (index == -1) { 
     165        lut[0][i] = (short) i; 
     166        lut[1][i] = (short) i; 
     167        lut[2][i] = (short) i; 
     168      } 
     169      else { 
     170        lut[index][i] = (short) i; 
     171      } 
     172    } 
     173 
     174    return lut; 
     175  } 
     176 
    122177  /** 
    123178   * @see loci.formats.IFormatReader#openBytes(int, byte[], int, int, int, int) 
     
    128183    FormatTools.checkPlaneParameters(this, no, buf.length, x, y, w, h); 
    129184 
    130     in.seek(offsets[series][no]); 
     185    lastChannel = split ? no % getSizeC() : 0; 
     186    int planeIndex = split ? no / getSizeC() : no; 
     187    in.seek(offsets[series][planeIndex]); 
    131188 
    132189    int bpp = FormatTools.getBytesPerPixel(getPixelType()); 
    133190    int pixel = bpp * getRGBChannelCount(); 
    134  
    135     long maxFP = no == getImageCount() - 1 ? 
    136       in.length() : offsets[series][no + 1]; 
     191    if (split) pixel *= getSizeC(); 
     192 
     193    int totalPlanes = split ? getImageCount() / getSizeC() : getImageCount(); 
     194 
     195    long maxFP = planeIndex == totalPlanes - 1 ? 
     196      in.length() : offsets[series][planeIndex + 1]; 
    137197 
    138198    CodecOptions options = new CodecOptions(); 
     
    141201    options.maxBytes = (int) maxFP; 
    142202 
    143     if (isJPEG) { 
    144       byte[] tmp = new JPEG2000Codec().decompress(in, options); 
    145       for (int row=y; row<h+y; row++) { 
    146         System.arraycopy(tmp, pixel * row * getSizeX(), buf, 
    147           pixel * w * (row - y), pixel * w); 
    148       } 
    149       System.arraycopy(tmp, 0, buf, 0, (int) Math.min(tmp.length, buf.length)); 
    150       tmp = null; 
    151     } 
    152     else if (isLossless) { 
    153       // plane is compressed using ZLIB 
    154  
    155       int effectiveX = getSizeX(); 
    156       if ((getSizeX() % 2) != 0) effectiveX++; 
    157       byte[] t = new ZlibCodec().decompress(in, options); 
    158  
    159       for (int row=0; row<h; row++) { 
    160         int offset = (row + y) * effectiveX * pixel + x * pixel; 
    161         if (offset + w * pixel <= t.length) { 
    162           System.arraycopy(t, offset, buf, row * w * pixel, w * pixel); 
    163         } 
    164       } 
     203    int scanlinePad = (isJPEG || !isLossless) ? 0 : getSizeX() % 2; 
     204 
     205    if (isJPEG || isLossless) { 
     206      if (codec == null) codec = createCodec(isJPEG); 
     207      byte[] t = codec.decompress(in, options); 
     208      copyPixels(x, y, w, h, bpp, scanlinePad, t, buf, split); 
     209      t = null; 
     210    } 
     211    else if (split) { 
     212      byte[] pix = new byte[(getSizeX() + scanlinePad) * getSizeY() * pixel]; 
     213      in.read(pix); 
     214      copyPixels(x, y, w, h, bpp, scanlinePad, pix, buf, split); 
     215      pix = null; 
    165216    } 
    166217    else { 
    167218      // plane is not compressed 
    168       readPlane(in, x, y, w, h, buf); 
     219      readPlane(in, x, y, w, h, scanlinePad, buf); 
    169220    } 
    170221 
     
    177228    if (!fileOnly) { 
    178229      offsets = null; 
    179       zs.clear(); 
    180       ts.clear(); 
    181230      isJPEG = isLossless = false; 
    182       numSeries = 0; 
     231      codec = null; 
    183232      tsT.clear(); 
    184233 
    185       pixelSizeX = pixelSizeY = pixelSizeZ = 0f; 
    186       voltage = mag = na = objectiveModel = immersion = correction = null; 
    187       channelNames = null; 
    188       binning = null; 
    189       speed = null; 
    190       gain = null; 
    191       temperature = null; 
    192       exposureTime = null; 
    193       modality = null; 
    194       exWave = null; 
    195       emWave = null; 
    196       power = null; 
    197       cameraModel = null; 
     234      fieldIndex = 0; 
     235      xOffset = yOffset = zOffset = 0; 
    198236      posX = posY = posZ = null; 
    199       fieldIndex = 0; 
    200       rois = null; 
    201       pinholeSize = null; 
     237      channelColors = null; 
     238      split = false; 
    202239    } 
    203240  } 
     
    209246    super.initFile(id); 
    210247 
    211     channelNames = new Vector<String>(); 
    212     binning = new Vector<String>(); 
    213     speed = new Vector<Float>(); 
    214     gain = new Vector<Float>(); 
    215     temperature = new Vector<Float>(); 
    216     exposureTime = new Vector<Float>(); 
    217     modality = new Vector<String>(); 
    218     exWave = new Vector<Integer>(); 
    219     emWave = new Vector<Integer>(); 
    220     power = new Vector<Integer>(); 
    221     rois = new Vector<Hashtable<String, String>>(); 
    222     posX = new Vector<Float>(); 
    223     posY = new Vector<Float>(); 
    224     posZ = new Vector<Float>(); 
    225  
    226248    in = new RandomAccessInputStream(id); 
     249 
     250    channelColors = new Hashtable<String, Integer>(); 
    227251 
    228252    if (in.read() == -38 && in.read() == -50) { 
     
    236260      // assemble offsets to each block 
    237261 
    238       Vector<Long> imageOffsets = new Vector<Long>(); 
    239       Vector<int[]> imageLengths = new Vector<int[]>(); 
    240       Vector<Long> xmlOffsets = new Vector<Long>(); 
    241       Vector<int[]> xmlLengths = new Vector<int[]>(); 
    242       Vector<Long> customDataOffsets = new Vector<Long>(); 
    243       Vector<int[]> customDataLengths = new Vector<int[]>(); 
     262      ArrayList<String> imageNames = new ArrayList<String>(); 
     263      ArrayList<Long> imageOffsets = new ArrayList<Long>(); 
     264      ArrayList<int[]> imageLengths = new ArrayList<int[]>(); 
     265      ArrayList<Long> customDataOffsets = new ArrayList<Long>(); 
     266      ArrayList<int[]> customDataLengths = new ArrayList<int[]>(); 
     267 
     268      ByteArrayHandle xml = new ByteArrayHandle(); 
     269      StringBuffer name = new StringBuffer(); 
    244270 
    245271      // search for blocks 
    246272      byte[] sigBytes = {-38, -50, -66, 10}; // 0xDACEBE0A 
    247       final String sig = new String(sigBytes); 
    248273      while (in.getFilePointer() < in.length() - 1 && in.getFilePointer() >= 0) 
    249274      { 
    250         in.findString(false, 1024, sig); // empirically, 1KB blocks work well 
     275        byte[] buf = new byte[1024]; 
     276        int foundIndex = -1; 
     277        in.read(buf, 0, sigBytes.length); 
     278        while (foundIndex == -1 && in.getFilePointer() < in.length()) { 
     279          int n = in.read(buf, sigBytes.length, buf.length - sigBytes.length); 
     280          for (int i=0; i<buf.length-sigBytes.length; i++) { 
     281            for (int j=0; j<sigBytes.length; j++) { 
     282              if (buf[i + j] != sigBytes[j]) break; 
     283              if (j == sigBytes.length - 1) foundIndex = i; 
     284            } 
     285            if (foundIndex != -1) break; 
     286          } 
     287          if (foundIndex == -1) { 
     288            System.arraycopy(buf, buf.length - sigBytes.length - 1, 
     289              buf, 0, sigBytes.length); 
     290          } 
     291          else in.seek(in.getFilePointer() - n + foundIndex); 
     292        } 
     293        if (in.getFilePointer() >= in.length() || foundIndex == -1) { 
     294          break; 
     295        } 
     296 
    251297        if (in.getFilePointer() > in.length() - 24) break; 
    252298 
     
    264310        int skip = len - 12 - lenOne * 2; 
    265311        if (skip <= 0) skip += lenOne * 2; 
    266         in.skipBytes(skip); 
    267312 
    268313        if (blockType.startsWith("ImageDataSeq")) { 
    269314          imageOffsets.add(new Long(fp)); 
    270315          imageLengths.add(new int[] {lenOne, lenTwo}); 
    271         } 
    272         else if (blockType.startsWith("Image")) { 
    273           xmlOffsets.add(new Long(fp)); 
    274           xmlLengths.add(new int[] {lenOne, lenTwo}); 
    275         } 
    276         else if (blockType.startsWith("CustomData|A")) { 
     316          char b = (char) in.readByte(); 
     317          while (b != '!') { 
     318            name.append(b); 
     319            b = (char) in.readByte(); 
     320          } 
     321          imageNames.add(name.toString()); 
     322          name = name.delete(0, name.length()); 
     323        } 
     324        else if (blockType.startsWith("Image") || 
     325          blockType.startsWith("CustomDataVa")) 
     326        { 
     327          int length = lenOne + lenTwo - 12; 
     328          byte[] b = new byte[length]; 
     329          in.read(b); 
     330 
     331          // strip out invalid characters 
     332          int off = 0; 
     333          for (int j=0; j<length; j++) { 
     334            char c = (char) b[j]; 
     335            if ((off == 0 && c == '!') || c == 0) off = j + 1; 
     336            if (Character.isISOControl(c) || !Character.isDefined(c)) { 
     337              b[j] = (byte) ' '; 
     338            } 
     339          } 
     340 
     341          if (length - off >= 5 && b[off] == '<' && b[off + 1] == '?' && 
     342            b[off + 2] == 'x' && b[off + 3] == 'm' && b[off + 4] == 'l') 
     343          { 
     344            boolean endBracketFound = false; 
     345            while (!endBracketFound) { 
     346              if (b[off++] == '>') { 
     347                endBracketFound = true; 
     348              } 
     349            } 
     350            xml.write(b, off, b.length - off); 
     351          } 
     352          skip = 0; 
     353        } 
     354        if (blockType.startsWith("CustomData|A")) { 
    277355          customDataOffsets.add(new Long(fp)); 
    278356          customDataLengths.add(new int[] {lenOne, lenTwo}); 
    279357        } 
     358        else if (blockType.startsWith("CustomData|Z")) { 
     359          int nDoubles = (lenOne + lenTwo) / 8; 
     360          zOffset = fp + 8 * (nDoubles - imageOffsets.size()); 
     361        } 
     362        else if (blockType.startsWith("CustomData|X")) { 
     363          int nDoubles = (lenOne + lenTwo) / 8; 
     364          xOffset = fp + 8 * (nDoubles - imageOffsets.size()); 
     365        } 
     366        else if (blockType.startsWith("CustomData|Y")) { 
     367          int nDoubles = (lenOne + lenTwo) / 8; 
     368          yOffset = fp + 8 * (nDoubles - imageOffsets.size()); 
     369        } 
     370        in.skipBytes(skip); 
    280371      } 
    281372 
    282373      // parse XML blocks 
    283374 
    284       DefaultHandler handler = new ND2Handler(); 
    285       ByteVector xml = new ByteVector(); 
    286  
    287       for (int i=0; i<xmlOffsets.size(); i++) { 
    288         long offset = xmlOffsets.get(i).longValue(); 
    289         int[] p = xmlLengths.get(i); 
    290         int length = p[0] + p[1]; 
    291  
    292         byte[] b = new byte[length]; 
    293         in.seek(offset); 
    294         in.read(b); 
    295  
    296         // strip out invalid characters 
    297         int off = 0; 
    298         for (int j=0; j<length; j++) { 
    299           char c = (char) b[j]; 
    300           if ((off == 0 && c == '!') || c == 0) off = j + 1; 
    301           if (Character.isISOControl(c) || !Character.isDefined(c)) { 
    302             b[j] = (byte) ' '; 
    303           } 
    304         } 
    305  
    306         if (length - off >= 5 && b[off] == '<' && b[off + 1] == '?' && 
    307           b[off + 2] == 'x' && b[off + 3] == 'm' && b[off + 4] == 'l') 
    308         { 
    309           boolean endBracketFound = false; 
    310           while (!endBracketFound) { 
    311             if (b[off++] == '>') { 
    312               endBracketFound = true; 
    313             } 
    314           } 
    315           xml.add(b, off, b.length - off); 
    316         } 
    317       } 
    318  
    319       String xmlString = new String(xml.toByteArray()); 
     375      String xmlString = new String(xml.getBytes(), 0, (int) xml.length()); 
    320376      xmlString = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><ND2>" + 
    321377        xmlString + "</ND2>"; 
     378      xmlString = XMLTools.sanitizeXML(xmlString); 
    322379 
    323380      core[0].dimensionOrder = ""; 
    324381 
     382      ND2Handler handler = new ND2Handler(core); 
    325383      XMLTools.parseXML(xmlString, handler); 
     384 
     385      channelColors = handler.getChannelColors(); 
     386      isLossless = handler.isLossless(); 
     387      fieldIndex = handler.getFieldIndex(); 
     388      core = handler.getCoreMetadata(); 
     389      Hashtable<String, Object> globalMetadata = handler.getMetadata(); 
     390      for (String key : globalMetadata.keySet()) { 
     391        addGlobalMeta(key, globalMetadata.get(key)); 
     392      } 
     393 
     394      int numSeries = handler.getSeriesCount(); 
    326395 
    327396      // rearrange image data offsets 
     
    389458      if (getDimensionOrder().equals("T")) { 
    390459        fieldIndex = 0; 
     460      } 
     461      else if (getDimensionOrder().equals("ZT") && fieldIndex == 2) { 
     462        fieldIndex--; 
    391463      } 
    392464 
     
    423495        int length = p[0] + p[1]; 
    424496 
    425         in.seek(offset); 
    426         byte[] b = new byte[p[0]]; 
    427         in.read(b); 
    428  
    429         StringBuffer sb = new StringBuffer(); 
    430         int pt = 13; 
    431         while (b[pt] != '!') { 
    432           sb.append((char) b[pt++]); 
    433         } 
    434         b = null; 
    435         int ndx = Integer.parseInt(sb.toString()); 
    436  
    437497        if (getSizeC() == 0) { 
    438498          int sizeC = length / (getSizeX() * getSizeY() * 
     
    443503        } 
    444504 
     505        String imageName = imageNames.get(i); 
     506        int ndx = Integer.parseInt(imageName.replaceAll("\\D", "")); 
     507 
    445508        int[] pos = FormatTools.rasterToPosition(lengths, ndx); 
    446509        int seriesIndex = pos[fieldIndex]; 
     
    454517      } 
    455518 
    456       Vector<long[]> tmpOffsets = new Vector<long[]>(); 
     519      ArrayList<long[]> tmpOffsets = new ArrayList<long[]>(); 
    457520      for (int i=0; i<offsets.length; i++) { 
    458521        if (offsets[i][0] > 0) tmpOffsets.add(offsets[i]); 
     
    504567      } 
    505568 
     569      split = getSizeC() > 1; 
    506570      for (int i=0; i<getSeriesCount(); i++) { 
    507         core[i].rgb = getSizeC() > 1; 
     571        core[i].rgb = false; 
    508572        core[i].littleEndian = true; 
    509         core[i].interleaved = true; 
    510         core[i].indexed = false; 
    511         core[i].falseColor = false; 
     573        core[i].interleaved = false; 
     574        core[i].indexed = channelColors.size() > 0; 
     575        core[i].falseColor = true; 
    512576        core[i].metadataComplete = true; 
    513         core[i].imageCount = core[i].sizeZ * core[i].sizeT; 
    514         if (!core[i].rgb) core[i].imageCount *= core[i].sizeC; 
     577        core[i].imageCount = core[i].sizeZ * core[i].sizeT * core[i].sizeC; 
    515578      } 
    516579 
    517580      // read first CustomData block 
     581 
     582      posX = handler.getXPositions(); 
     583      posY = handler.getYPositions(); 
     584      posZ = handler.getZPositions(); 
    518585 
    519586      if (customDataOffsets.size() > 0) { 
     
    529596        for (int series=0; series<getSeriesCount(); series++) { 
    530597          setSeries(series); 
    531           for (int plane=0; plane<getImageCount(); plane++) { 
     598          int count = split ? getImageCount() / getSizeC() : getImageCount(); 
     599          for (int plane=0; plane<count; plane++) { 
    532600            // timestamps are stored in ms; we want them in seconds 
    533601            double time = in.readDouble() / 1000; 
    534             tsT.add(new Float(time)); 
     602            tsT.add(new Double(time)); 
    535603            addSeriesMeta("timestamp " + plane, time); 
    536604          } 
     
    539607      } 
    540608 
    541       populateMetadataStore(); 
     609      if (posX.size() == 0 && xOffset != 0) { 
     610        in.seek(xOffset); 
     611        for (int i=0; i<imageOffsets.size(); i++) { 
     612          posX.add(new Double(in.readDouble())); 
     613        } 
     614      } 
     615      if (posY.size() == 0 && yOffset != 0) { 
     616        in.seek(yOffset); 
     617        for (int i=0; i<imageOffsets.size(); i++) { 
     618          posY.add(new Double(in.readDouble())); 
     619        } 
     620      } 
     621      if (posZ.size() == 0 && zOffset != 0) { 
     622        in.seek(zOffset); 
     623        for (int i=0; i<imageOffsets.size(); i++) { 
     624          posZ.add(new Double(in.readDouble())); 
     625        } 
     626      } 
     627 
     628      populateMetadataStore(handler); 
    542629      return; 
    543630    } 
     
    550637    status("Calculating image offsets"); 
    551638 
    552     Vector<Long> vs = new Vector<Long>(); 
     639    ArrayList<Long> vs = new ArrayList<Long>(); 
    553640 
    554641    long pos = in.getFilePointer(); 
     
    624711    status("Parsing XML"); 
    625712 
     713    ArrayList<Long> zs = new ArrayList<Long>(); 
     714    ArrayList<Long> ts = new ArrayList<Long>(); 
     715 
     716    int numSeries = 0; 
     717    ND2Handler handler = null; 
    626718    if (off > 0 && off < in.length() - 5 && (in.length() - off - 5) > 14) { 
    627719      in.seek(off + 4); 
     
    661753      status("Finished assembling XML string"); 
    662754 
    663       DefaultHandler handler = new ND2Handler(); 
    664  
    665755      // strip out invalid characters 
    666756      int offset = 0; 
     
    678768 
    679769      String xml = sb.toString().substring(offset, len - offset); 
     770      handler = new ND2Handler(core); 
    680771      XMLTools.parseXML(xml, handler); 
    681772      xml = null; 
     773 
     774      isLossless = handler.isLossless(); 
     775      fieldIndex = handler.getFieldIndex(); 
     776      zs = handler.getZSections(); 
     777      ts = handler.getTimepoints(); 
     778      numSeries = handler.getSeriesCount(); 
     779      core = handler.getCoreMetadata(); 
     780      Hashtable<String, Object> globalMetadata = handler.getMetadata(); 
     781      for (String key : globalMetadata.keySet()) { 
     782        addGlobalMeta(key, globalMetadata.get(key)); 
     783      } 
    682784    } 
    683785 
     
    756858    } 
    757859 
    758     populateMetadataStore(); 
     860    populateMetadataStore(handler); 
    759861  } 
    760862 
    761   // -- Helper class -- 
    762  
    763   /** SAX handler for parsing XML. */ 
    764   class ND2Handler extends DefaultHandler { 
    765     private String prefix = null; 
    766     private String prevRuntype = null; 
    767     private String prevElement = null; 
    768  
    769     public void endElement(String uri, String localName, String qName, 
    770       Attributes attributes) 
    771     { 
    772       if (qName.equals("CalibrationSeq") || qName.equals("MetadataSeq")) { 
    773         prefix = null; 
    774       } 
    775       if (qName.equals(prevElement)) { 
    776         prevElement = null; 
    777       } 
    778     } 
    779  
    780     public void startElement(String uri, String localName, String qName, 
    781       Attributes attributes) 
    782     { 
    783       if ("CLxListVariant".equals(attributes.getValue("runtype"))) { 
    784         prevElement = qName; 
    785       } 
    786  
    787       String value = attributes.getValue("value"); 
    788       if (qName.equals("uiWidth")) { 
    789         core[0].sizeX = Integer.parseInt(value); 
    790       } 
    791       else if (qName.equals("uiWidthBytes") || qName.equals("uiBpcInMemory")) { 
    792         int div = qName.equals("uiWidthBytes") ? getSizeX() : 8; 
    793         int bytes = Integer.parseInt(value) / div; 
    794  
    795         switch (bytes) { 
    796           case 2: 
    797             core[0].pixelType = FormatTools.UINT16; 
    798             break; 
    799           case 4: 
    800             core[0].pixelType = FormatTools.UINT32; 
    801             break; 
    802           default: 
    803             core[0].pixelType = FormatTools.UINT8; 
    804         } 
    805         parseKeyAndValue(qName, value, prevRuntype); 
    806       } 
    807       else if ("dPosX".equals(prevElement) && qName.startsWith("item_")) { 
    808         posX.add(new Float(sanitizeFloat(value))); 
    809       } 
    810       else if ("dPosY".equals(prevElement) && qName.startsWith("item_")) { 
    811         posY.add(new Float(sanitizeFloat(value))); 
    812       } 
    813       else if ("dPosZ".equals(prevElement) && qName.startsWith("item_")) { 
    814         posZ.add(new Float(sanitizeFloat(value))); 
    815       } 
    816       else if (qName.startsWith("item_")) { 
    817         int v = Integer.parseInt(qName.substring(qName.indexOf("_") + 1)); 
    818         if (v == numSeries) { 
    819           fieldIndex = getDimensionOrder().length(); 
    820           numSeries++; 
    821         } 
    822       } 
    823       else if (qName.equals("uiCompCount")) { 
    824         int v = Integer.parseInt(value); 
    825         core[0].sizeC = (int) Math.max(getSizeC(), v); 
    826       } 
    827       else if (qName.equals("uiHeight")) { 
    828         core[0].sizeY = Integer.parseInt(value); 
    829       } 
    830       else if (qName.startsWith("TextInfo")) { 
    831         parseKeyAndValue(qName, attributes.getValue("Text"), prevRuntype); 
    832         parseKeyAndValue(qName, value, prevRuntype); 
    833       } 
    834       else if (qName.equals("dCompressionParam")) { 
    835         isLossless = Integer.parseInt(value) > 0; 
    836         parseKeyAndValue(qName, value, prevRuntype); 
    837       } 
    838       else if (qName.equals("CalibrationSeq") || qName.equals("MetadataSeq")) { 
    839         prefix = qName + " " + attributes.getValue("_SEQUENCE_INDEX"); 
    840       } 
    841       else if (qName.equals("HorizontalLine") || qName.equals("VerticalLine") || 
    842         qName.equals("Text")) 
    843       { 
    844         Hashtable<String, String> roi = new Hashtable<String, String>(); 
    845         roi.put("ROIType", qName); 
    846         for (int q=0; q<attributes.getLength(); q++) { 
    847           roi.put(attributes.getQName(q), attributes.getValue(q)); 
    848         } 
    849         rois.add(roi); 
    850       } 
    851       else if (qName.equals("dPinholeRadius")) { 
    852         pinholeSize = new Float(sanitizeFloat(value)); 
    853         addGlobalMeta("Pinhole size", value); 
    854       } 
    855       else { 
    856         StringBuffer sb = new StringBuffer(); 
    857         if (prefix != null) { 
    858           sb.append(prefix); 
    859           sb.append(" "); 
    860         } 
    861         sb.append(qName); 
    862         parseKeyAndValue(sb.toString(), value, prevRuntype); 
    863       } 
    864  
    865       prevRuntype = attributes.getValue("runtype"); 
    866     } 
    867   } 
    868  
    869863  // -- Helper methods -- 
    870864 
    871   private void populateMetadataStore() { 
     865  private void populateMetadataStore(ND2Handler handler) throws FormatException 
     866  { 
    872867    MetadataStore store = 
    873868      new FilterMetadata(getMetadataStore(), isMetadataFiltered()); 
    874869    MetadataTools.populatePixels(store, this, true); 
    875870 
    876     String instrumentID = MetadataTools.createLSID("Instrument", 0); 
    877     store.setInstrumentID(instrumentID, 0); 
    878  
    879     // populate Image data 
    880871    String filename = new Location(getCurrentFile()).getName(); 
    881872    for (int i=0; i<getSeriesCount(); i++) { 
    882873      store.setImageName(filename + " (series " + (i + 1) + ")", i); 
    883874      MetadataTools.setDefaultCreationDate(store, currentId, i); 
    884  
     875    } 
     876 
     877    colors = new int[getEffectiveSizeC()]; 
     878 
     879    ArrayList<String> channelNames = null; 
     880    if (handler != null) { 
     881      channelNames = handler.getChannelNames(); 
     882      for (int i=0; i<getSeriesCount(); i++) { 
     883        for (int c=0; c<getEffectiveSizeC(); c++) { 
     884          int index = i * getSizeC() + c; 
     885          if (index < channelNames.size()) { 
     886            String channelName = channelNames.get(index); 
     887            Integer channelColor = channelColors.get(channelName); 
     888            colors[c] = channelColor == null ? 0 : channelColor.intValue(); 
     889          } 
     890        } 
     891      } 
     892    } 
     893 
     894    String instrumentID = MetadataTools.createLSID("Instrument", 0); 
     895    store.setInstrumentID(instrumentID, 0); 
     896 
     897    for (int i=0; i<getSeriesCount(); i++) { 
    885898      // link Instrument and Image 
    886899      store.setImageInstrumentRef(instrumentID, i); 
     
    888901 
    889902    // populate Dimensions data 
    890     for (int i=0; i<getSeriesCount(); i++) { 
    891       store.setDimensionsPhysicalSizeX(new Float(pixelSizeX), i, 0); 
    892       store.setDimensionsPhysicalSizeY(new Float(pixelSizeY), i, 0); 
    893       store.setDimensionsPhysicalSizeZ(new Float(pixelSizeZ), i, 0); 
     903    if (handler != null) { 
     904      for (int i=0; i<getSeriesCount(); i++) { 
     905        store.setDimensionsPhysicalSizeX((float) handler.getPixelSizeX(), i, 0); 
     906        store.setDimensionsPhysicalSizeY((float) handler.getPixelSizeY(), i, 0); 
     907        store.setDimensionsPhysicalSizeZ((float) handler.getPixelSizeZ(), i, 0); 
     908      } 
    894909    } 
    895910 
    896911    // populate PlaneTiming and StagePosition data 
     912    ArrayList<Double> exposureTime = null; 
     913    if (handler != null) handler.getExposureTimes(); 
    897914    for (int i=0; i<getSeriesCount(); i++) { 
    898915      if (tsT.size() > 0) { 
     
    902919          int stampIndex = coords[2] + i * getSizeT(); 
    903920          if (tsT.size() == getImageCount()) stampIndex = n; 
    904           double stamp = tsT.get(stampIndex).doubleValue(); 
    905           store.setPlaneTimingDeltaT(new Float(stamp), i, 0, n); 
     921          float stamp = tsT.get(stampIndex).floatValue(); 
     922          store.setPlaneTimingDeltaT(stamp, i, 0, n); 
    906923 
    907924          int index = i * getSizeC() + coords[1]; 
    908           if (index < exposureTime.size()) { 
    909             store.setPlaneTimingExposureTime(exposureTime.get(index), i, 0, n); 
    910           } 
    911         } 
    912       } 
     925          if (exposureTime != null && index < exposureTime.size()) { 
     926            store.setPlaneTimingExposureTime( 
     927              exposureTime.get(index).floatValue(), i, 0, n); 
     928          } 
     929        } 
     930      } 
     931 
     932      if (handler != null) { 
     933        if (posX == null) posX = handler.getXPositions(); 
     934        if (posY == null) posY = handler.getYPositions(); 
     935        if (posZ == null) posZ = handler.getZPositions(); 
     936      } 
     937 
     938      String pos = "for position #" + (i + 1); 
    913939      for (int n=0; n<getImageCount(); n++) { 
    914         if (i < posX.size()) { 
    915           store.setStagePositionPositionX(posX.get(i), i, 0, n); 
    916           addSeriesMeta("X position", posX.get(i)); 
    917           addGlobalMeta("X position for position #" + (i + 1), posX.get(i)); 
    918         } 
    919         if (i < posY.size()) { 
    920           store.setStagePositionPositionY(posY.get(i), i, 0, n); 
    921           addSeriesMeta("Y position" + (i + 1), posY.get(i)); 
    922           addGlobalMeta("X position for position #" + (i + 1), posX.get(i)); 
    923         } 
    924         if (i < posZ.size()) { 
    925           store.setStagePositionPositionZ(posZ.get(i), i, 0, n); 
    926           addSeriesMeta("Z position" + (i + 1), posZ.get(i)); 
    927           addGlobalMeta("X position for position #" + (i + 1), posX.get(i)); 
    928         } 
    929  
    930       } 
     940        int index = i * getImageCount() + n; 
     941        if (posX != null) { 
     942          if (index >= posX.size()) index = i; 
     943          if (index < posX.size()) { 
     944            String key = "X position "; 
     945            store.setStagePositionPositionX( 
     946              posX.get(index).floatValue(), i, 0, n); 
     947            addSeriesMeta(key + (i + 1), posX.get(index)); 
     948            addGlobalMeta(key + pos, posX.get(index)); 
     949          } 
     950        } 
     951        if (posY != null) { 
     952          if (index < posY.size()) { 
     953            String key = "Y position "; 
     954            store.setStagePositionPositionY( 
     955              posY.get(index).floatValue(), i, 0, n); 
     956            addSeriesMeta(key + (i + 1), posY.get(index)); 
     957            addGlobalMeta(key + pos, posY.get(index)); 
     958          } 
     959        } 
     960        if (posZ != null) { 
     961          if (index < posZ.size()) { 
     962            store.setStagePositionPositionZ( 
     963              posZ.get(index).floatValue(), i, 0, n); 
     964            String key = "Z position " + pos + ", plane #" + (n + 1); 
     965            addSeriesMeta(key, posZ.get(index)); 
     966            addGlobalMeta(key, posZ.get(index)); 
     967          } 
     968        } 
     969      } 
     970    } 
     971 
     972    if (handler == null) { 
     973      setSeries(0); 
     974      return; 
    931975    } 
    932976 
    933977    String detectorID = MetadataTools.createLSID("Detector", 0, 0); 
    934978    store.setDetectorID(detectorID, 0, 0); 
    935     store.setDetectorModel(cameraModel, 0, 0); 
    936     store.setDetectorType("Unknown", 0, 0); 
     979    store.setDetectorModel(handler.getCameraModel(), 0, 0); 
     980    store.setDetectorType("Other", 0, 0); 
     981 
     982    ArrayList<String> modality = handler.getModalities(); 
     983    ArrayList<String> binning = handler.getBinnings(); 
     984    ArrayList<Double> speed = handler.getSpeeds(); 
     985    ArrayList<Double> gain = handler.getGains(); 
     986    ArrayList<Double> temperature = handler.getTemperatures(); 
     987    ArrayList<Integer> exWave = handler.getExcitationWavelengths(); 
     988    ArrayList<Integer> emWave = handler.getEmissionWavelengths(); 
     989    ArrayList<Integer> power = handler.getPowers(); 
     990    ArrayList<Hashtable<String, String>> rois = handler.getROIs(); 
    937991 
    938992    for (int i=0; i<getSeriesCount(); i++) { 
    939993      for (int c=0; c<getEffectiveSizeC(); c++) { 
    940994        int index = i * getSizeC() + c; 
     995        Float pinholeSize = handler.getPinholeSize().floatValue(); 
    941996        if (pinholeSize != null) { 
    942997          store.setLogicalChannelPinholeSize(pinholeSize, i, c); 
    943998        } 
    944999        if (index < channelNames.size()) { 
    945           store.setLogicalChannelName(channelNames.get(index), i, c); 
     1000          String channelName = channelNames.get(index); 
     1001          store.setLogicalChannelName(channelName, i, c); 
    9461002        } 
    9471003        if (index < modality.size()) { 
     
    9581014        } 
    9591015        if (index < gain.size()) { 
    960           store.setDetectorSettingsGain(gain.get(index), i, c); 
     1016          store.setDetectorSettingsGain(gain.get(index).floatValue(), i, c); 
    9611017        } 
    9621018        if (index < speed.size()) { 
    963           store.setDetectorSettingsReadOutRate(speed.get(index), i, c); 
     1019          store.setDetectorSettingsReadOutRate( 
     1020            speed.get(index).floatValue(), i, c); 
    9641021        } 
    9651022        store.setDetectorSettingsDetector(detectorID, i, c); 
     
    9691026    for (int i=0; i<getSeriesCount(); i++) { 
    9701027      if (i * getSizeC() < temperature.size()) { 
    971         Float temp = temperature.get(i * getSizeC()); 
     1028        Float temp = temperature.get(i * getSizeC()).floatValue(); 
    9721029        store.setImagingEnvironmentTemperature(temp, i); 
    9731030      } 
     
    9751032 
    9761033    // populate DetectorSettings 
     1034    Double voltage = handler.getVoltage(); 
    9771035    if (voltage != null) { 
    978       voltage = sanitizeFloat(voltage); 
    979       store.setDetectorSettingsVoltage(new Float(voltage), 0, 0); 
     1036      store.setDetectorSettingsVoltage(voltage.floatValue(), 0, 0); 
    9801037    } 
    9811038 
    9821039    // populate Objective 
     1040    Double na = handler.getNumericalAperture(); 
    9831041    if (na != null) { 
    984       na = sanitizeFloat(na); 
    985       store.setObjectiveLensNA(new Float(na), 0, 0); 
    986     } 
     1042      store.setObjectiveLensNA(na.floatValue(), 0, 0); 
     1043    } 
     1044    Double mag = handler.getMagnification(); 
    9871045    if (mag != null) { 
    988       mag = sanitizeFloat(mag); 
    989       store.setObjectiveCalibratedMagnification(new Float(mag), 0, 0); 
    990     } 
    991     if (objectiveModel != null) { 
    992       store.setObjectiveModel(objectiveModel, 0, 0); 
    993     } 
    994     if (immersion == null) immersion = "Unknown"; 
     1046      store.setObjectiveCalibratedMagnification(mag.floatValue(), 0, 0); 
     1047    } 
     1048    store.setObjectiveModel(handler.getObjectiveModel(), 0, 0); 
     1049 
     1050    String immersion = handler.getImmersion(); 
     1051    if (immersion == null) immersion = "Other"; 
    9951052    store.setObjectiveImmersion(immersion, 0, 0); 
    996     if (correction == null || correction.length() == 0) correction = "Unknown"; 
     1053 
     1054    String correction = handler.getCorrection(); 
     1055    if (correction == null || correction.length() == 0) correction = "Other"; 
    9971056    store.setObjectiveCorrection(correction, 0, 0); 
    9981057 
     
    10001059    String objectiveID = MetadataTools.createLSID("Objective", 0, 0); 
    10011060    store.setObjectiveID(objectiveID, 0, 0); 
     1061 
     1062    Double refractiveIndex = handler.getRefractiveIndex(); 
     1063 
    10021064    for (int i=0; i<getSeriesCount(); i++) { 
    1003       store.setObjectiveSettingsObjective(objectiveID, 0); 
     1065      store.setObjectiveSettingsObjective(objectiveID, i); 
     1066      if (refractiveIndex != null) { 
     1067        store.setObjectiveSettingsRefractiveIndex( 
     1068          refractiveIndex.floatValue(), i); 
     1069      } 
    10041070    } 
    10051071 
     
    10081074    // populate ROI data 
    10091075 
    1010     for (int r=0; r<rois.size(); r++) { 
    1011       Hashtable<String, String> roi = rois.get(r); 
    1012       String type = roi.get("ROIType"); 
    1013  
    1014       store.setShapeLocked(new Boolean(roi.get("locked")), 0, r, 0); 
    1015       store.setShapeStrokeWidth(new Integer(roi.get("line-width")), 0, r, 0); 
    1016       store.setShapeVisibility(new Boolean(roi.get("visible")), 0, r, 0); 
    1017       store.setShapeStrokeColor(roi.get("color"), 0, r, 0); 
    1018  
    1019       if (type.equals("Text")) { 
    1020         store.setShapeFontFamily(roi.get("fFaceName"), 0, r, 0); 
    1021         store.setShapeFontSize(new Integer(roi.get("fHeight")), 0, r, 0); 
    1022         store.setShapeText(roi.get("eval-text"), 0, r, 0); 
    1023         store.setShapeFontWeight(roi.get("fWeight"), 0, r, 0); 
    1024  
    1025         boolean italic = Integer.parseInt(roi.get("fItalic")) != 0; 
    1026         boolean underline = Integer.parseInt(roi.get("fUnderline")) != 0; 
    1027         boolean strikeOut = Integer.parseInt(roi.get("fStrikeOut")) != 0; 
    1028         store.setShapeFontStyle(italic ? "italic" : "normal", 0, r, 0); 
    1029         store.setShapeTextDecoration(underline ? "underline" : strikeOut ? 
    1030           "line-through" : "normal", 0, r, 0); 
    1031  
    1032         String rectangle = roi.get("rectangle"); 
    1033         String[] p = rectangle.split(","); 
    1034         double[] points = new double[p.length]; 
    1035         for (int i=0; i<p.length; i++) { 
    1036           points[i] = Double.parseDouble(p[i]); 
    1037         } 
    1038  
    1039         store.setRectX(p[0], 0, r, 0); 
    1040         store.setRectY(p[1], 0, r, 0); 
    1041         store.setRectWidth(String.valueOf(points[2] - points[0]), 0, r, 0); 
    1042         store.setRectHeight(String.valueOf(points[3] - points[1]), 0, r, 0); 
    1043       } 
    1044       else if (type.equals("HorizontalLine") || type.equals("VerticalLine")) { 
    1045         String segments = roi.get("segments"); 
    1046         segments = segments.replaceAll("\\[", ""); 
    1047         segments = segments.replaceAll("\\]", ""); 
    1048         String[] points = segments.split("\\)"); 
    1049  
    1050         StringBuffer sb = new StringBuffer(); 
    1051         for (int i=0; i<points.length; i++) { 
    1052           points[i] = points[i].substring(points[i].indexOf(":") + 1); 
    1053           sb.append(points[i]); 
    1054           if (i < points.length - 1) sb.append(" "); 
    1055         } 
    1056         store.setPolylinePoints(sb.toString(), 0, r, 0); 
    1057       } 
    1058     } 
     1076    handler.populateROIs(store); 
    10591077  } 
    10601078 
    1061   private void parseKeyAndValue(String key, String value, String runtype) { 
    1062     if (key == null || value == null) return; 
    1063     addGlobalMeta(key, value); 
    1064     if (key.endsWith("dCalibration")) { 
    1065       pixelSizeX = Float.parseFloat(sanitizeFloat(value)); 
    1066       pixelSizeY = pixelSizeX; 
    1067     } 
    1068     else if (key.endsWith("dZStep")) { 
    1069       pixelSizeZ = Float.parseFloat(sanitizeFloat(value)); 
    1070     } 
    1071     else if (key.endsWith("Gain")) gain.add(new Float(sanitizeFloat(value))); 
    1072     else if (key.endsWith("dLampVoltage")) voltage = value; 
    1073     else if (key.endsWith("dObjectiveMag") && mag == null) mag = value; 
    1074     else if (key.endsWith("dObjectiveNA")) na = value; 
    1075     else if (key.equals("sObjective") || key.equals("wsObjectiveName")) { 
    1076       String[] tokens = value.split(" "); 
    1077       int magIndex = -1; 
    1078       for (int i=0; i<tokens.length; i++) { 
    1079         if (tokens[i].indexOf("x") != -1) { 
    1080           magIndex = i; 
    1081           break; 
    1082         } 
    1083       } 
    1084       StringBuffer s = new StringBuffer(); 
    1085       for (int i=0; i<magIndex; i++) { 
    1086         s.append(tokens[i]); 
    1087       } 
    1088       correction = s.toString(); 
    1089       if (magIndex >= 0) { 
    1090         mag = tokens[magIndex].substring(0, tokens[magIndex].indexOf("x")); 
    1091       } 
    1092       if (magIndex + 1 < tokens.length) immersion = tokens[magIndex + 1]; 
    1093     } 
    1094     else if (key.endsWith("dTimeMSec")) { 
    1095       long v = (long) Float.parseFloat(sanitizeFloat(value)); 
    1096       if (!ts.contains(new Long(v))) { 
    1097         ts.add(new Long(v)); 
    1098         addGlobalMeta("number of timepoints", ts.size()); 
    1099       } 
    1100     } 
    1101     else if (key.endsWith("dZPos")) { 
    1102       long v = (long) Float.parseFloat(sanitizeFloat(value)); 
    1103       if (!zs.contains(new Long(v))) { 
    1104         zs.add(new Long(v)); 
    1105       } 
    1106     } 
    1107     else if (key.endsWith("uiCount")) { 
    1108       if (runtype != null) { 
    1109         if (runtype.endsWith("ZStackLoop")) { 
    1110           if (getSizeZ() == 0) { 
    1111             core[0].sizeZ = Integer.parseInt(value); 
    1112             if (getDimensionOrder().indexOf("Z") == -1) { 
    1113               core[0].dimensionOrder = "Z" + getDimensionOrder(); 
    1114             } 
    1115           } 
    1116         } 
    1117         else if (runtype.endsWith("TimeLoop")) { 
    1118           if (getSizeT() == 0) { 
    1119             core[0].sizeT = Integer.parseInt(value); 
    1120             if (getDimensionOrder().indexOf("T") == -1) { 
    1121               core[0].dimensionOrder = "T" + getDimensionOrder(); 
    1122             } 
    1123           } 
    1124         } 
    1125       } 
    1126     } 
    1127     else if (key.equals("VirtualComponents")) { 
    1128       if (getSizeC() == 0) { 
    1129         core[0].sizeC = Integer.parseInt(value); 
    1130         if (getDimensionOrder().indexOf("C") == -1) { 
    1131           core[0].dimensionOrder += "C" + getDimensionOrder(); 
    1132         } 
    1133       } 
    1134     } 
    1135     else if (key.startsWith("TextInfoItem") || key.endsWith("TextInfoItem")) { 
    1136       metadata.remove(key); 
    1137       value = value.replaceAll("&#x000d;&#x000a;", "\n"); 
    1138       StringTokenizer tokens = new StringTokenizer(value, "\n"); 
    1139       while (tokens.hasMoreTokens()) { 
    1140         String t = tokens.nextToken().trim(); 
    1141         if (t.startsWith("Dimensions:")) { 
    1142           t = t.substring(11); 
    1143           StringTokenizer dims = new StringTokenizer(t, " x "); 
    1144  
    1145           core[0].sizeZ = 1; 
    1146           core[0].sizeT = 1; 
    1147           core[0].sizeC = 1; 
    1148  
    1149           while (dims.hasMoreTokens()) { 
    1150             String dim = dims.nextToken().trim(); 
    1151             int v = Integer.parseInt(dim.replaceAll("\\D", "")); 
    1152             v = (int) Math.max(v, 1); 
    1153             if (dim.startsWith("XY")) { 
    1154               numSeries = v; 
    1155               if (numSeries > 1) { 
    1156                 int x = getSizeX(); 
    1157                 int y = getSizeY(); 
    1158                 int z = getSizeZ(); 
    1159                 int tSize = getSizeT(); 
    1160                 int c = getSizeC(); 
    1161                 String order = getDimensionOrder(); 
    1162                 core = new CoreMetadata[numSeries]; 
    1163                 for (int i=0; i<numSeries; i++) { 
    1164                   core[i] = new CoreMetadata(); 
    1165                   core[i].sizeX = x; 
    1166                   core[i].sizeY = y; 
    1167                   core[i].sizeZ = z == 0 ? 1 : z; 
    1168                   core[i].sizeC = c == 0 ? 1 : c; 
    1169                   core[i].sizeT = tSize == 0 ? 1 : tSize; 
    1170                   core[i].dimensionOrder = order; 
    1171                 } 
    1172               } 
    1173             } 
    1174             else if (dim.startsWith("T")) core[0].sizeT = v; 
    1175             else if (dim.startsWith("Z")) core[0].sizeZ = v; 
    1176             else { 
    1177               core[0].sizeC = v; 
    1178             } 
    1179           } 
    1180  
    1181           core[0].imageCount = getSizeZ() * getSizeC() * getSizeT(); 
    1182         } 
    1183         else if (t.startsWith("Number of Picture Planes")) { 
    1184           core[0].sizeC = Integer.parseInt(t.replaceAll("\\D", "")); 
    1185         } 
    1186         else { 
    1187           String[] v = t.split(":"); 
    1188           if (v.length == 2) { 
    1189             v[1] = v[1].trim(); 
    1190             if (v[0].equals("Name")) { 
    1191               channelNames.add(v[1]); 
    1192             } 
    1193             else if (v[0].equals("Modality")) { 
    1194               modality.add(v[1]); 
    1195             } 
    1196             else if (v[0].equals("Camera Type")) { 
    1197               cameraModel = v[1]; 
    1198             } 
    1199             else if (v[0].equals("Binning")) { 
    1200               binning.add(v[1]); 
    1201             } 
    1202             else if (v[0].equals("Readout Speed")) { 
    1203               int last = v[1].lastIndexOf(" "); 
    1204               if (last != -1) v[1] = v[1].substring(0, last); 
    1205               speed.add(new Float(sanitizeFloat(v[1]))); 
    1206             } 
    1207             else if (v[0].equals("Temperature")) { 
    1208               String temp = v[1].replaceAll("[\\D&&[^-.]]", ""); 
    1209               temperature.add(new Float(sanitizeFloat(temp))); 
    1210             } 
    1211             else if (v[0].equals("Exposure")) { 
    1212               String[] s = v[1].trim().split(" "); 
    1213               try { 
    1214                 float time = Float.parseFloat(sanitizeFloat(s[0])); 
    1215                 // TODO: check for other units 
    1216                 if (s[1].equals("ms")) time /= 1000; 
    1217                 exposureTime.add(new Float(time)); 
    1218               } 
    1219               catch (NumberFormatException e) { } 
    1220             } 
    1221           } 
    1222           else if (v[0].startsWith("- Step")) { 
    1223             int space = v[0].indexOf(" ", v[0].indexOf("Step") + 1); 
    1224             int last = v[0].indexOf(" ", space + 1); 
    1225             if (last == -1) last = v[0].length(); 
    1226             pixelSizeZ = 
    1227               Float.parseFloat(sanitizeFloat(v[0].substring(space, last))); 
    1228           } 
    1229           else if (v[0].equals("Line")) { 
    1230             String[] values = t.split(";"); 
    1231             for (int q=0; q<values.length; q++) { 
    1232               int colon = values[q].indexOf(":"); 
    1233               if (colon < 0) continue; 
    1234               String nextKey = values[q].substring(0, colon).trim(); 
    1235               String nextValue = values[q].substring(colon + 1).trim(); 
    1236               if (nextKey.equals("Emission wavelength")) { 
    1237                 emWave.add(new Integer(nextValue)); 
    1238               } 
    1239               else if (nextKey.equals("Excitation wavelength")) { 
    1240                 exWave.add(new Integer(nextValue)); 
    1241               } 
    1242               else if (nextKey.equals("Power")) { 
    1243                 nextValue = sanitizeFloat(nextValue); 
    1244                 power.add(new Integer((int) Float.parseFloat(nextValue))); 
    1245               } 
    1246             } 
    1247           } 
    1248         } 
    1249       } 
    1250     } 
     1079  private Codec createCodec(boolean isJPEG) { 
     1080    return isJPEG ? new JPEG2000Codec() : new ZlibCodec(); 
    12511081  } 
    12521082 
    1253   private String sanitizeFloat(String value) { 
    1254     char separator = new DecimalFormatSymbols().getDecimalSeparator(); 
    1255     if (value.indexOf(separator) == -1) { 
    1256       char usedSeparator = separator == '.' ? ',' : '.'; 
    1257       value = value.replace(usedSeparator, separator); 
    1258     } 
    1259     return value; 
     1083  private void copyPixels(int x, int y, int w, int h, int bpp, int scanlinePad, 
     1084    byte[] pix, byte[] buf, boolean split) 
     1085    throws IOException 
     1086  { 
     1087    if (split) { 
     1088      pix = ImageTools.splitChannels(pix, lastChannel, getEffectiveSizeC(), bpp, 
     1089        false, true); 
     1090    } 
     1091    RandomAccessInputStream s = new RandomAccessInputStream(pix); 
     1092    readPlane(s, x, y, w, h, scanlinePad, buf); 
     1093    s.close(); 
    12601094  } 
    12611095 
Note: See TracChangeset for help on using the changeset viewer.