Changeset 6494


Ignore:
Timestamp:
06/05/10 11:50:35 (10 years ago)
Author:
melissa
Message:

Added support for multi-file OME-TIFF export. Closes #485.

Files:
8 edited

Legend:

Unmodified
Added
Removed
  • branches/4.2/components/bio-formats/src/loci/formats/in/OMETiffReader.java

    r6459 r6494  
    203203  public String[] getSeriesUsedFiles(boolean noPixels) { 
    204204    FormatTools.assertId(currentId, true, 1); 
    205     return noPixels ? null : used; 
     205    if (noPixels) return null; 
     206    Vector<String> usedFiles = new Vector<String>(); 
     207    for (int i=0; i<info[series].length; i++) { 
     208      if (!usedFiles.contains(info[series][i].id)) { 
     209        usedFiles.add(info[series][i].id); 
     210      } 
     211    } 
     212    return usedFiles.toArray(new String[usedFiles.size()]); 
    206213  } 
    207214 
  • branches/4.2/components/bio-formats/src/loci/formats/out/OMETiffWriter.java

    r6294 r6494  
    3131import loci.common.Location; 
    3232import loci.common.RandomAccessInputStream; 
     33import loci.common.RandomAccessOutputStream; 
    3334import loci.common.services.DependencyException; 
    3435import loci.common.services.ServiceException; 
     
    6768  private ArrayList<Integer> seriesMap; 
    6869  private boolean wroteLast; 
     70  private String[][] imageLocations; 
     71  private int totalPlanes = 0; 
    6972 
    7073  // -- Constructor -- 
     
    8083    if (currentId != null) { 
    8184      if (!wroteLast) { 
    82         // FIXME 
    83         throw new IOException( 
    84           "Sorry, closing OME-TIFF files early is not yet supported."); 
     85        super.close(); 
     86        return; 
    8587      } 
    8688 
     
    106108      } 
    107109 
    108       // generate UUID and add to OME element 
    109       String filename = new Location(currentId).getName(); 
    110       String uuid = "urn:uuid:" + getUUID(filename); 
    111       omeMeta.setUUID(uuid); 
    112  
    113110      for (int series=0; series<omeMeta.getImageCount(); series++) { 
    114111        String dimensionOrder = 
     
    118115        int sizeT = omeMeta.getPixelsSizeT(series).getValue().intValue(); 
    119116 
    120         int imageCount = 0; 
     117        int imageCount = getPlaneCount(); 
    121118        int ifdCount = seriesMap.size(); 
    122         for (int q=0; q<ifdCount; q++) { 
    123           if (seriesMap.get(q).intValue() == series) imageCount++; 
    124         } 
    125119 
    126120        if (imageCount == 0) { 
    127121          omeMeta.setTiffDataPlaneCount(new Integer(0), series, 0); 
    128122          continue; 
    129         } 
    130  
    131         // if RGB planes were written, adjust sizeC 
    132         if (imageCount < sizeZ * sizeC * sizeT) { 
    133           sizeC = imageCount / (sizeZ * sizeT); 
    134123        } 
    135124 
     
    140129        } 
    141130 
    142         int ifd = 0, plane = 0; 
    143         while (plane < imageCount) { 
    144           // skip past IFDs from other series 
    145           while (seriesMap.get(ifd).intValue() != series) { 
    146             ifd++; 
    147           } 
    148           // determine number of sequential IFDs 
    149           int end = ifd; 
    150           while (end < ifdCount && seriesMap.get(end).intValue() == series) { 
    151             end++; 
    152           } 
    153           int num = end - ifd; 
    154  
    155           // fill in filename and UUID values 
     131        HashMap<String, Integer> ifdCounts = new HashMap<String, Integer>(); 
     132 
     133        for (int plane=0; plane<imageCount; plane++) { 
    156134          int[] zct = FormatTools.getZCTCoords(dimensionOrder, 
    157135            sizeZ, sizeC, sizeT, imageCount, plane); 
     136          String filename = 
     137            new Location(imageLocations[series][plane]).getName(); 
     138 
     139          Integer ifdIndex = ifdCounts.get(filename); 
     140          int ifd = ifdIndex == null ? 0 : ifdIndex.intValue(); 
     141 
    158142          omeMeta.setUUIDFileName(filename, series, plane); 
    159           // TODO 
    160           //omeMeta.setTiffDataUUID(uuid, series, 0, plane); 
     143          String uuid = "urn:uuid:" + getUUID(filename); 
     144          omeMeta.setUUIDValue(uuid, series, plane); 
    161145          // fill in any non-default TiffData attributes 
    162           if (zct[0] > 0) { 
    163             omeMeta.setTiffDataFirstZ(new Integer(zct[0]), series, plane); 
    164           } 
    165           if (zct[1] > 0) { 
    166             omeMeta.setTiffDataFirstC(new Integer(zct[1]), series, plane); 
    167           } 
    168           if (zct[2] > 0) { 
    169             omeMeta.setTiffDataFirstT(new Integer(zct[2]), series, plane); 
    170           } 
    171           if (ifd > 0) { 
    172             omeMeta.setTiffDataIFD(new Integer(ifd), series, plane); 
    173           } 
    174           if (num != ifdCount) { 
    175             omeMeta.setTiffDataPlaneCount(new Integer(num), series, plane); 
    176           } 
    177           plane += num; 
    178           ifd = end; 
    179         } 
    180       } 
    181  
    182       String xml; 
    183       try { 
    184         xml = service.getOMEXML(omeMeta); 
    185       } 
    186       catch (ServiceException se) { 
    187         // FIXME: Modify close() signature to include FormatException? 
    188         // throw new FormatException(se); 
    189         throw new RuntimeException(se); 
    190       } 
    191  
    192       // insert warning comment 
    193       String prefix = xml.substring(0, xml.indexOf(">") + 1); 
    194       String suffix = xml.substring(xml.indexOf(">") + 1); 
    195       xml = prefix + WARNING_COMMENT + suffix; 
    196  
    197       // write OME-XML to the first IFD's comment 
    198       try { 
    199         TiffSaver saver = new TiffSaver(out); 
    200         RandomAccessInputStream in = new RandomAccessInputStream(currentId); 
    201         saver.overwriteComment(in, xml); 
    202         in.close(); 
    203       } 
    204       catch (FormatException exc) { 
    205         IOException io = new IOException("Unable to append OME-XML comment"); 
    206         io.initCause(exc); 
    207         throw io; 
     146          omeMeta.setTiffDataFirstZ(zct[0], series, plane); 
     147          omeMeta.setTiffDataFirstC(zct[1], series, plane); 
     148          omeMeta.setTiffDataFirstT(new Integer(zct[2]), series, plane); 
     149          omeMeta.setTiffDataIFD(ifd, series, plane); 
     150          omeMeta.setTiffDataPlaneCount(1, series, plane); 
     151 
     152          ifdCounts.put(filename, ifd + 1); 
     153        } 
     154      } 
     155 
     156      ArrayList<String> files = new ArrayList<String>(); 
     157      for (String[] s : imageLocations) { 
     158        for (String f : s) { 
     159          if (!files.contains(f)) files.add(f); 
     160        } 
     161      } 
     162 
     163      for (String file : files) { 
     164        // generate UUID and add to OME element 
     165        String uuid = "urn:uuid:" + getUUID(new Location(file).getName()); 
     166        omeMeta.setUUID(uuid); 
     167 
     168        String xml; 
     169        try { 
     170          xml = service.getOMEXML(omeMeta); 
     171        } 
     172        catch (ServiceException se) { 
     173          // FIXME: Modify close() signature to include FormatException? 
     174          // throw new FormatException(se); 
     175          throw new RuntimeException(se); 
     176        } 
     177 
     178        // insert warning comment 
     179        String prefix = xml.substring(0, xml.indexOf(">") + 1); 
     180        String suffix = xml.substring(xml.indexOf(">") + 1); 
     181        xml = prefix + WARNING_COMMENT + suffix; 
     182 
     183        if (out != null) out.close(); 
     184        out = new RandomAccessOutputStream(file); 
     185 
     186        // write OME-XML to the first IFD's comment 
     187        try { 
     188          TiffSaver saver = new TiffSaver(out); 
     189          RandomAccessInputStream in = new RandomAccessInputStream(file); 
     190          saver.overwriteLastIFDOffset(in); 
     191          saver.overwriteComment(in, xml); 
     192          in.close(); 
     193        } 
     194        catch (FormatException exc) { 
     195          IOException io = new IOException("Unable to append OME-XML comment"); 
     196          io.initCause(exc); 
     197          throw io; 
     198        } 
    208199      } 
    209200    } 
    210201    super.close(); 
    211202    seriesMap = null; 
     203    imageLocations = null; 
    212204    wroteLast = false; 
     205    totalPlanes = 0; 
    213206  } 
    214207 
     
    226219    MetadataRetrieve r = getMetadataRetrieve(); 
    227220 
    228     wroteLast = series == r.getImageCount() - 1 && no == getPlaneCount() - 1; 
    229221    super.saveBytes(no, buf, x, y, w, h); 
     222 
     223    int index = totalPlanes; 
     224    int currentSeries = series; 
     225    for (int s=0; s<currentSeries; s++) { 
     226      setSeries(s); 
     227      index -= getPlaneCount(); 
     228    } 
     229    setSeries(currentSeries); 
     230 
     231    imageLocations[series][index] = currentId; 
     232    totalPlanes++; 
     233 
     234    wroteLast = series == r.getImageCount() - 1 && index == getPlaneCount() - 1; 
    230235  } 
    231236 
     
    235240  public void setId(String id) throws FormatException, IOException { 
    236241    if (id.equals(currentId)) return; 
    237     Location file = new Location(id); 
    238     if (file.exists() && file.length() > 0) { 
    239       // FIXME 
    240       throw new FormatException( 
    241         "Sorry, appending to existing OME-TIFF files is not yet supported."); 
    242     } 
    243242    super.setId(id); 
     243    if (imageLocations == null) { 
     244      MetadataRetrieve r = getMetadataRetrieve(); 
     245      imageLocations = new String[r.getImageCount()][]; 
     246      for (int i=0; i<imageLocations.length; i++) { 
     247        setSeries(i); 
     248        imageLocations[i] = new String[getPlaneCount()]; 
     249      } 
     250      setSeries(0); 
     251    } 
    244252  } 
    245253 
  • branches/4.2/components/bio-formats/src/loci/formats/tiff/TiffSaver.java

    r6298 r6494  
    447447  } 
    448448 
     449  public void overwriteLastIFDOffset(RandomAccessInputStream raf) 
     450    throws FormatException, IOException 
     451  { 
     452    TiffParser parser = new TiffParser(raf); 
     453    long[] offsets = parser.getIFDOffsets(); 
     454    out.seek(raf.getFilePointer() - (bigTiff ? 8 : 4)); 
     455    writeIntValue(out, 0); 
     456  } 
     457 
    449458  /** 
    450459   * Surgically overwrites an existing IFD value with the given one. This 
  • branches/4.2/components/bio-formats/utils/MultiFileExportExample.java

    r6294 r6494  
    22 
    33import loci.formats.FormatException; 
     4import loci.formats.FormatTools; 
    45import loci.formats.ImageReader; 
    56import loci.formats.ImageWriter; 
     
    1415    if (args.length < 2) { 
    1516      System.out.println( 
    16         "Usage: java MultiFileExportExample <infile> <output file extension"); 
     17        "Usage: java MultiFileExportExample <infile> <output file extension>"); 
    1718      System.exit(1); 
    1819    } 
     
    3738        writer.changeOutputFile(file); 
    3839        for (int image=0; image<planesPerFile; image++) { 
    39           writer.saveBytes(image, reader.openBytes(image)); 
     40          int[] zct = FormatTools.getZCTCoords(reader.getDimensionOrder(), 
     41            1, reader.getEffectiveSizeC(), reader.getSizeT(), 
     42            planesPerFile, image); 
     43          int index = FormatTools.getIndex(reader, z, zct[1], zct[2]); 
     44          writer.saveBytes(image, reader.openBytes(index)); 
    4045        } 
    4146      } 
  • trunk/components/bio-formats/src/loci/formats/in/OMETiffReader.java

    r6459 r6494  
    203203  public String[] getSeriesUsedFiles(boolean noPixels) { 
    204204    FormatTools.assertId(currentId, true, 1); 
    205     return noPixels ? null : used; 
     205    if (noPixels) return null; 
     206    Vector<String> usedFiles = new Vector<String>(); 
     207    for (int i=0; i<info[series].length; i++) { 
     208      if (!usedFiles.contains(info[series][i].id)) { 
     209        usedFiles.add(info[series][i].id); 
     210      } 
     211    } 
     212    return usedFiles.toArray(new String[usedFiles.size()]); 
    206213  } 
    207214 
  • trunk/components/bio-formats/src/loci/formats/out/OMETiffWriter.java

    r6294 r6494  
    3131import loci.common.Location; 
    3232import loci.common.RandomAccessInputStream; 
     33import loci.common.RandomAccessOutputStream; 
    3334import loci.common.services.DependencyException; 
    3435import loci.common.services.ServiceException; 
     
    6768  private ArrayList<Integer> seriesMap; 
    6869  private boolean wroteLast; 
     70  private String[][] imageLocations; 
     71  private int totalPlanes = 0; 
    6972 
    7073  // -- Constructor -- 
     
    8083    if (currentId != null) { 
    8184      if (!wroteLast) { 
    82         // FIXME 
    83         throw new IOException( 
    84           "Sorry, closing OME-TIFF files early is not yet supported."); 
     85        super.close(); 
     86        return; 
    8587      } 
    8688 
     
    106108      } 
    107109 
    108       // generate UUID and add to OME element 
    109       String filename = new Location(currentId).getName(); 
    110       String uuid = "urn:uuid:" + getUUID(filename); 
    111       omeMeta.setUUID(uuid); 
    112  
    113110      for (int series=0; series<omeMeta.getImageCount(); series++) { 
    114111        String dimensionOrder = 
     
    118115        int sizeT = omeMeta.getPixelsSizeT(series).getValue().intValue(); 
    119116 
    120         int imageCount = 0; 
     117        int imageCount = getPlaneCount(); 
    121118        int ifdCount = seriesMap.size(); 
    122         for (int q=0; q<ifdCount; q++) { 
    123           if (seriesMap.get(q).intValue() == series) imageCount++; 
    124         } 
    125119 
    126120        if (imageCount == 0) { 
    127121          omeMeta.setTiffDataPlaneCount(new Integer(0), series, 0); 
    128122          continue; 
    129         } 
    130  
    131         // if RGB planes were written, adjust sizeC 
    132         if (imageCount < sizeZ * sizeC * sizeT) { 
    133           sizeC = imageCount / (sizeZ * sizeT); 
    134123        } 
    135124 
     
    140129        } 
    141130 
    142         int ifd = 0, plane = 0; 
    143         while (plane < imageCount) { 
    144           // skip past IFDs from other series 
    145           while (seriesMap.get(ifd).intValue() != series) { 
    146             ifd++; 
    147           } 
    148           // determine number of sequential IFDs 
    149           int end = ifd; 
    150           while (end < ifdCount && seriesMap.get(end).intValue() == series) { 
    151             end++; 
    152           } 
    153           int num = end - ifd; 
    154  
    155           // fill in filename and UUID values 
     131        HashMap<String, Integer> ifdCounts = new HashMap<String, Integer>(); 
     132 
     133        for (int plane=0; plane<imageCount; plane++) { 
    156134          int[] zct = FormatTools.getZCTCoords(dimensionOrder, 
    157135            sizeZ, sizeC, sizeT, imageCount, plane); 
     136          String filename = 
     137            new Location(imageLocations[series][plane]).getName(); 
     138 
     139          Integer ifdIndex = ifdCounts.get(filename); 
     140          int ifd = ifdIndex == null ? 0 : ifdIndex.intValue(); 
     141 
    158142          omeMeta.setUUIDFileName(filename, series, plane); 
    159           // TODO 
    160           //omeMeta.setTiffDataUUID(uuid, series, 0, plane); 
     143          String uuid = "urn:uuid:" + getUUID(filename); 
     144          omeMeta.setUUIDValue(uuid, series, plane); 
    161145          // fill in any non-default TiffData attributes 
    162           if (zct[0] > 0) { 
    163             omeMeta.setTiffDataFirstZ(new Integer(zct[0]), series, plane); 
    164           } 
    165           if (zct[1] > 0) { 
    166             omeMeta.setTiffDataFirstC(new Integer(zct[1]), series, plane); 
    167           } 
    168           if (zct[2] > 0) { 
    169             omeMeta.setTiffDataFirstT(new Integer(zct[2]), series, plane); 
    170           } 
    171           if (ifd > 0) { 
    172             omeMeta.setTiffDataIFD(new Integer(ifd), series, plane); 
    173           } 
    174           if (num != ifdCount) { 
    175             omeMeta.setTiffDataPlaneCount(new Integer(num), series, plane); 
    176           } 
    177           plane += num; 
    178           ifd = end; 
    179         } 
    180       } 
    181  
    182       String xml; 
    183       try { 
    184         xml = service.getOMEXML(omeMeta); 
    185       } 
    186       catch (ServiceException se) { 
    187         // FIXME: Modify close() signature to include FormatException? 
    188         // throw new FormatException(se); 
    189         throw new RuntimeException(se); 
    190       } 
    191  
    192       // insert warning comment 
    193       String prefix = xml.substring(0, xml.indexOf(">") + 1); 
    194       String suffix = xml.substring(xml.indexOf(">") + 1); 
    195       xml = prefix + WARNING_COMMENT + suffix; 
    196  
    197       // write OME-XML to the first IFD's comment 
    198       try { 
    199         TiffSaver saver = new TiffSaver(out); 
    200         RandomAccessInputStream in = new RandomAccessInputStream(currentId); 
    201         saver.overwriteComment(in, xml); 
    202         in.close(); 
    203       } 
    204       catch (FormatException exc) { 
    205         IOException io = new IOException("Unable to append OME-XML comment"); 
    206         io.initCause(exc); 
    207         throw io; 
     146          omeMeta.setTiffDataFirstZ(zct[0], series, plane); 
     147          omeMeta.setTiffDataFirstC(zct[1], series, plane); 
     148          omeMeta.setTiffDataFirstT(new Integer(zct[2]), series, plane); 
     149          omeMeta.setTiffDataIFD(ifd, series, plane); 
     150          omeMeta.setTiffDataPlaneCount(1, series, plane); 
     151 
     152          ifdCounts.put(filename, ifd + 1); 
     153        } 
     154      } 
     155 
     156      ArrayList<String> files = new ArrayList<String>(); 
     157      for (String[] s : imageLocations) { 
     158        for (String f : s) { 
     159          if (!files.contains(f)) files.add(f); 
     160        } 
     161      } 
     162 
     163      for (String file : files) { 
     164        // generate UUID and add to OME element 
     165        String uuid = "urn:uuid:" + getUUID(new Location(file).getName()); 
     166        omeMeta.setUUID(uuid); 
     167 
     168        String xml; 
     169        try { 
     170          xml = service.getOMEXML(omeMeta); 
     171        } 
     172        catch (ServiceException se) { 
     173          // FIXME: Modify close() signature to include FormatException? 
     174          // throw new FormatException(se); 
     175          throw new RuntimeException(se); 
     176        } 
     177 
     178        // insert warning comment 
     179        String prefix = xml.substring(0, xml.indexOf(">") + 1); 
     180        String suffix = xml.substring(xml.indexOf(">") + 1); 
     181        xml = prefix + WARNING_COMMENT + suffix; 
     182 
     183        if (out != null) out.close(); 
     184        out = new RandomAccessOutputStream(file); 
     185 
     186        // write OME-XML to the first IFD's comment 
     187        try { 
     188          TiffSaver saver = new TiffSaver(out); 
     189          RandomAccessInputStream in = new RandomAccessInputStream(file); 
     190          saver.overwriteLastIFDOffset(in); 
     191          saver.overwriteComment(in, xml); 
     192          in.close(); 
     193        } 
     194        catch (FormatException exc) { 
     195          IOException io = new IOException("Unable to append OME-XML comment"); 
     196          io.initCause(exc); 
     197          throw io; 
     198        } 
    208199      } 
    209200    } 
    210201    super.close(); 
    211202    seriesMap = null; 
     203    imageLocations = null; 
    212204    wroteLast = false; 
     205    totalPlanes = 0; 
    213206  } 
    214207 
     
    226219    MetadataRetrieve r = getMetadataRetrieve(); 
    227220 
    228     wroteLast = series == r.getImageCount() - 1 && no == getPlaneCount() - 1; 
    229221    super.saveBytes(no, buf, x, y, w, h); 
     222 
     223    int index = totalPlanes; 
     224    int currentSeries = series; 
     225    for (int s=0; s<currentSeries; s++) { 
     226      setSeries(s); 
     227      index -= getPlaneCount(); 
     228    } 
     229    setSeries(currentSeries); 
     230 
     231    imageLocations[series][index] = currentId; 
     232    totalPlanes++; 
     233 
     234    wroteLast = series == r.getImageCount() - 1 && index == getPlaneCount() - 1; 
    230235  } 
    231236 
     
    235240  public void setId(String id) throws FormatException, IOException { 
    236241    if (id.equals(currentId)) return; 
    237     Location file = new Location(id); 
    238     if (file.exists() && file.length() > 0) { 
    239       // FIXME 
    240       throw new FormatException( 
    241         "Sorry, appending to existing OME-TIFF files is not yet supported."); 
    242     } 
    243242    super.setId(id); 
     243    if (imageLocations == null) { 
     244      MetadataRetrieve r = getMetadataRetrieve(); 
     245      imageLocations = new String[r.getImageCount()][]; 
     246      for (int i=0; i<imageLocations.length; i++) { 
     247        setSeries(i); 
     248        imageLocations[i] = new String[getPlaneCount()]; 
     249      } 
     250      setSeries(0); 
     251    } 
    244252  } 
    245253 
  • trunk/components/bio-formats/src/loci/formats/tiff/TiffSaver.java

    r6298 r6494  
    447447  } 
    448448 
     449  public void overwriteLastIFDOffset(RandomAccessInputStream raf) 
     450    throws FormatException, IOException 
     451  { 
     452    TiffParser parser = new TiffParser(raf); 
     453    long[] offsets = parser.getIFDOffsets(); 
     454    out.seek(raf.getFilePointer() - (bigTiff ? 8 : 4)); 
     455    writeIntValue(out, 0); 
     456  } 
     457 
    449458  /** 
    450459   * Surgically overwrites an existing IFD value with the given one. This 
  • trunk/components/bio-formats/utils/MultiFileExportExample.java

    r6294 r6494  
    22 
    33import loci.formats.FormatException; 
     4import loci.formats.FormatTools; 
    45import loci.formats.ImageReader; 
    56import loci.formats.ImageWriter; 
     
    1415    if (args.length < 2) { 
    1516      System.out.println( 
    16         "Usage: java MultiFileExportExample <infile> <output file extension"); 
     17        "Usage: java MultiFileExportExample <infile> <output file extension>"); 
    1718      System.exit(1); 
    1819    } 
     
    3738        writer.changeOutputFile(file); 
    3839        for (int image=0; image<planesPerFile; image++) { 
    39           writer.saveBytes(image, reader.openBytes(image)); 
     40          int zct[] = FormatTools.getZCTCoords(reader.getDimensionOrder(), 
     41            1, reader.getEffectiveSizeC(), reader.getSizeT(), 
     42            planesPerFile, image); 
     43          int index = FormatTools.getIndex(reader, z, zct[1], zct[2]); 
     44          writer.saveBytes(image, reader.openBytes(index)); 
    4045        } 
    4146      } 
Note: See TracChangeset for help on using the changeset viewer.