コード例 #1
0
ファイル: WrapperTest.java プロジェクト: knabar/bioformats
 @DataProvider(name = "wrappers")
 public Object[][] createWrappers() {
   Location.mapId(TEST_FILE, TEST_FILE);
   Object[][] wrappers =
       new Object[][] {
         {new ChannelFiller()},
         {new ChannelMerger()},
         {new ChannelSeparator()},
         {new DimensionSwapper()},
         {new FileStitcher()},
         {new ImageReader()},
         {new MinMaxCalculator()}
       };
   for (int i = 0; i < wrappers.length; i++) {
     IFormatReader reader = (IFormatReader) wrappers[i][0];
     try {
       reader.setId(TEST_FILE);
     } catch (FormatException e) {
       e.printStackTrace();
     } catch (IOException e) {
       e.printStackTrace();
     }
   }
   return wrappers;
 }
コード例 #2
0
ファイル: ImageOpener.java プロジェクト: Jondeen/imglib
 /**
  * Reads in an imglib {@link Image} from the given source (e.g., file on disk), using the given
  * {@link ContainerFactory} to construct the {@link Image}.
  */
 public <T extends RealType<T>> Image<T> openImage(String id, ContainerFactory containerFactory)
     throws FormatException, IOException {
   final IFormatReader r = initializeReader(id);
   final T type = makeType(r.getPixelType());
   final ImageFactory<T> imageFactory = new ImageFactory<T>(type, containerFactory);
   return openImage(r, imageFactory);
 }
コード例 #3
0
  /**
   * Tests whether Bio-Formats is potentially capable of importing the given file IDs. Outputs the
   * IDs it can potentially import, one group per line, with elements of the each group separated by
   * spaces.
   */
  public void testIds(int[] fileIds) throws OmeisException, FormatException, IOException {
    Arrays.sort(fileIds);

    // set up file path mappings
    String[] ids = new String[fileIds.length];
    for (int i = 0; i < fileIds.length; i++) {
      Hashtable fileInfo = getFileInfo(fileIds[i]);
      ids[i] = (String) fileInfo.get("Name");
      String path = getLocalFilePath(fileIds[i]);
      Location.mapId(ids[i], path);
    }

    // check types and groups
    if (http) printHttpResponseHeader();
    boolean[] done = new boolean[fileIds.length];
    StringBuffer sb = new StringBuffer();
    for (int i = 0; i < fileIds.length; i++) {
      if (done[i]) continue; // already part of another group
      if (ids[i] == null) continue; // invalid id
      if (!reader.isThisType(ids[i])) continue; // unknown format
      reader.setId(ids[i]);
      String[] files = reader.getUsedFiles();

      if (files == null) continue; // invalid files list
      sb.setLength(0);

      for (int j = files.length - 1; j >= 0; j--) {
        for (int ii = i; ii < fileIds.length; ii++) {
          if (files[j] == null) {
            log("Warning: FileID " + fileIds[ii] + " ('" + ids[ii] + "') has null used file #" + j);
          } else if (files[j].equals(ids[ii])) {
            if (done[ii]) {
              log(
                  "Warning: FileID "
                      + fileIds[ii]
                      + " ('"
                      + ids[ii]
                      + "') already belongs to a group");
            }
            done[ii] = true;
            if (j < files.length - 1) sb.append(" ");
            sb.append(fileIds[ii]);
            break;
          }
        }
      }
      System.out.println(sb.toString());
    }
  }
コード例 #4
0
ファイル: ImageOpener.java プロジェクト: Jondeen/imglib
 @SuppressWarnings({"rawtypes", "unchecked"})
 private void populatePlane(IFormatReader r, int no, byte[] plane, PlanarAccess planarAccess) {
   final int pixelType = r.getPixelType();
   final int bpp = FormatTools.getBytesPerPixel(pixelType);
   final boolean fp = FormatTools.isFloatingPoint(pixelType);
   final boolean little = r.isLittleEndian();
   Object planeArray = DataTools.makeDataArray(plane, bpp, fp, little);
   if (planeArray == plane) {
     // array was returned by reference; make a copy
     final byte[] planeCopy = new byte[plane.length];
     System.arraycopy(plane, 0, planeCopy, 0, plane.length);
     planeArray = planeCopy;
   }
   planarAccess.setPlane(no, makeArray(planeArray));
 }
コード例 #5
0
  public OmeisImporter(boolean stitchFiles) {
    stitch = stitchFiles;
    reader = new ChannelSeparator(new ChannelFiller());
    if (stitch) reader = new FileStitcher(reader);

    try {
      ServiceFactory factory = new ServiceFactory();
      OMEXMLService service = factory.getInstance(OMEXMLService.class);
      omexmlMeta = (AbstractOMEXMLMetadata) service.createOMEXMLMetadata();
    } catch (DependencyException de) {
    } catch (ServiceException se) {
    }

    reader.setOriginalMetadataPopulated(true);
    reader.setMetadataStore(omexmlMeta);
  }
コード例 #6
0
ファイル: ImageOpener.java プロジェクト: Jondeen/imglib
  /** Constructs and initializes a Bio-Formats reader for the given file. */
  private IFormatReader initializeReader(String id) throws FormatException, IOException {
    notifyListeners(new StatusEvent("Initializing " + id));

    IFormatReader r = null;
    r = new ImageReader();
    r = new ChannelFiller(r);
    r = new ChannelSeparator(r);

    try {
      r.setMetadataStore(new OMEXMLServiceImpl().createOMEXMLMetadata());
    } catch (ServiceException e) {
    }

    r.setId(id);

    return r;
  }
コード例 #7
0
ファイル: ImageOpener.java プロジェクト: Jondeen/imglib
  private <T extends RealType<T>> void populatePlane(
      IFormatReader r, int no, byte[] plane, LocalizablePlaneCursor<T> cursor) {
    final int sizeX = r.getSizeX();
    final int pixelType = r.getPixelType();
    final boolean little = r.isLittleEndian();

    final int[] dimLengths = getDimLengths(r);
    final int[] pos = new int[dimLengths.length];

    final int planeX = 0;
    final int planeY = 1;

    getPosition(r, no, pos);
    cursor.reset(planeX, planeY, pos);

    while (cursor.hasNext()) {
      cursor.fwd();
      final int index = cursor.getPosition(planeX) + cursor.getPosition(planeY) * sizeX;
      final double value = decodeWord(plane, index, pixelType, little);
      cursor.getType().setReal(value);
    }
  }
コード例 #8
0
 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
   if ("equals".equals(method.getName())) {
     throw new UnsupportedOperationException();
   } else if ("hashCode".equals(method.getName())) {
     return Integer.valueOf(reader.hashCode());
   } else if ("toString".equals(method.getName())) {
     return "ReaderHandler [" + reader + "]";
   } else {
     try {
       return method.invoke(proxy, args);
     } catch (Exception e) {
       throw new FormatException(e);
     }
   }
 }
コード例 #9
0
ファイル: ImageOpener.java プロジェクト: Jondeen/imglib
  /** Retrieves calibration for X,Y,Z,T * */
  private float[] getCalibration(final IFormatReader r, final int[] dimensions) {
    float[] calibration = new float[dimensions.length];
    for (int i = 0; i < calibration.length; ++i) calibration[i] = 1;

    try {
      final String dimOrder = r.getDimensionOrder().toUpperCase();
      final MetadataRetrieve retrieve = (MetadataRetrieve) r.getMetadataStore();

      PositiveFloat cal;

      final int posX = dimOrder.indexOf('X');
      cal = retrieve.getPixelsPhysicalSizeX(0);
      if (posX >= 0 && posX < calibration.length && cal != null && cal.getValue() != 0)
        calibration[posX] = cal.getValue().floatValue();

      final int posY = dimOrder.indexOf('Y');
      cal = retrieve.getPixelsPhysicalSizeY(0);
      if (posY >= 0 && posY < calibration.length && cal != null && cal.getValue() != 0)
        calibration[posY] = cal.getValue().floatValue();

      final int posZ = dimOrder.indexOf('Z');
      cal = retrieve.getPixelsPhysicalSizeZ(0);
      if (posZ >= 0 && posZ < calibration.length && cal != null && cal.getValue() != 0)
        calibration[posZ] = cal.getValue().floatValue();

      final int posT = dimOrder.indexOf('T');
      retrieve.getPixelsTimeIncrement(0);
      Double cal1 = retrieve.getPixelsTimeIncrement(0);
      if (posT >= 0 && posT < calibration.length && cal1 != null && cal1.floatValue() != 0)
        calibration[posT] = cal1.floatValue();
    } catch (Exception e) {
      // somehow an error occured reading the calibration
    }

    return calibration;
  }
コード例 #10
0
ファイル: ImageOpener.java プロジェクト: Jondeen/imglib
  /** Compiles an N-dimensional list of axis lengths from the given reader. */
  private int[] getDimLengths(IFormatReader r) {
    final int sizeX = r.getSizeX();
    final int sizeY = r.getSizeY();
    final int sizeZ = r.getSizeZ();
    final int sizeT = r.getSizeT();
    // final String[] cDimTypes = r.getChannelDimTypes();
    final int[] cDimLengths = r.getChannelDimLengths();
    final String dimOrder = r.getDimensionOrder();

    final List<Integer> dimLengthsList = new ArrayList<Integer>();

    // add core dimensions
    for (int i = 0; i < dimOrder.length(); i++) {
      final char dim = dimOrder.charAt(i);
      switch (dim) {
        case 'X':
          if (sizeX > 1) dimLengthsList.add(sizeX);
          break;
        case 'Y':
          if (sizeY > 1) dimLengthsList.add(sizeY);
          break;
        case 'Z':
          if (sizeZ > 1) dimLengthsList.add(sizeZ);
          break;
        case 'T':
          if (sizeT > 1) dimLengthsList.add(sizeT);
          break;
        case 'C':
          for (int c = 0; c < cDimLengths.length; c++) {
            int len = cDimLengths[c];
            if (len > 1) dimLengthsList.add(len);
          }
          break;
      }
    }

    // convert result to primitive array
    final int[] dimLengths = new int[dimLengthsList.size()];
    for (int i = 0; i < dimLengths.length; i++) {
      dimLengths[i] = dimLengthsList.get(i);
    }
    return dimLengths;
  }
コード例 #11
0
ファイル: ImageOpener.java プロジェクト: Jondeen/imglib
  /** Copies the current dimensional position into the given array. */
  private void getPosition(IFormatReader r, int no, int[] pos) {
    final int sizeX = r.getSizeX();
    final int sizeY = r.getSizeY();
    final int sizeZ = r.getSizeZ();
    final int sizeT = r.getSizeT();
    // final String[] cDimTypes = r.getChannelDimTypes();
    final int[] cDimLengths = r.getChannelDimLengths();
    final String dimOrder = r.getDimensionOrder();

    final int[] zct = r.getZCTCoords(no);

    int index = 0;
    for (int i = 0; i < dimOrder.length(); i++) {
      final char dim = dimOrder.charAt(i);
      switch (dim) {
        case 'X':
          if (sizeX > 1) index++; // NB: Leave X axis position alone.
          break;
        case 'Y':
          if (sizeY > 1) index++; // NB: Leave Y axis position alone.
          break;
        case 'Z':
          if (sizeZ > 1) pos[index++] = zct[0];
          break;
        case 'T':
          if (sizeT > 1) pos[index++] = zct[2];
          break;
        case 'C':
          final int[] cPos = FormatTools.rasterToPosition(cDimLengths, zct[1]);
          for (int c = 0; c < cDimLengths.length; c++) {
            if (cDimLengths[c] > 1) pos[index++] = cPos[c];
          }
          break;
      }
    }
  }
コード例 #12
0
ファイル: ImageOpener.java プロジェクト: Jondeen/imglib
  /** Compiles an N-dimensional list of axis types from the given reader. */
  private String[] getDimTypes(IFormatReader r) {
    final int sizeX = r.getSizeX();
    final int sizeY = r.getSizeY();
    final int sizeZ = r.getSizeZ();
    final int sizeT = r.getSizeT();
    final String[] cDimTypes = r.getChannelDimTypes();
    final int[] cDimLengths = r.getChannelDimLengths();
    final String dimOrder = r.getDimensionOrder();
    final List<String> dimTypes = new ArrayList<String>();

    // add core dimensions
    for (char dim : dimOrder.toCharArray()) {
      switch (dim) {
        case 'X':
          if (sizeX > 1) dimTypes.add(X);
          break;
        case 'Y':
          if (sizeY > 1) dimTypes.add(Y);
          break;
        case 'Z':
          if (sizeZ > 1) dimTypes.add(Z);
          break;
        case 'T':
          if (sizeT > 1) dimTypes.add(TIME);
          break;
        case 'C':
          for (int c = 0; c < cDimTypes.length; c++) {
            int len = cDimLengths[c];
            if (len > 1) dimTypes.add(cDimTypes[c]);
          }
          break;
      }
    }

    return dimTypes.toArray(new String[0]);
  }
コード例 #13
0
  public void init(Helper helper) {
    this.helper = helper;
    helper.setSteps(5);

    final ImportConfig config = new ImportConfig();
    final String sessionUuid = helper.getEventContext().getCurrentSessionUuid();

    if (!(location instanceof ManagedImportLocationI)) {
      throw helper.cancel(
          new ERR(), null, "bad-location", "location-type", location.getClass().getName());
    }

    ManagedImportLocationI managedLocation = (ManagedImportLocationI) location;
    logPath = managedLocation.getLogFile();
    logFilename = logPath.getFullFsPath();
    MDC.put("fileset", logFilename);

    file = ((ManagedImportLocationI) location).getTarget();

    try {
      sf = reg.getInternalServiceFactory(sessionUuid, "unused", 3, 1, clientUuid);
      store = new OMEROMetadataStoreClient();
      store.setCurrentLogFile(logFilename, token);
      store.initialize(sf);
      registerKeepAlive();

      fileName = file.getFullFsPath();
      shortName = file.getName();
      format = null;
      usedFiles = new String[] {fileName};

      open(reader, store, file);
      format = reader.getFormat();
      if (reader.getUsedFiles() != null) {
        usedFiles = reader.getUsedFiles();
      }
      if (usedFiles == null) {
        throw new NullPointerException("usedFiles must be non-null");
      }

      // Process all information which has been passed in as annotations
      detectKnownAnnotations();

      // Now that we've possibly updated the settings object, copy out
      // all the values needed by import.
      userSpecifiedTarget = settings.userSpecifiedTarget;
      userSpecifiedName =
          settings.userSpecifiedName == null ? null : settings.userSpecifiedName.getValue();
      userSpecifiedDescription =
          settings.userSpecifiedDescription == null
              ? null
              : settings.userSpecifiedDescription.getValue();
      userPixels = settings.userSpecifiedPixels;
      annotationList = settings.userSpecifiedAnnotationList;
      doThumbnails = settings.doThumbnails == null ? true : settings.doThumbnails.getValue();
      noStatsInfo = settings.noStatsInfo == null ? false : settings.noStatsInfo.getValue();

      IFormatReader baseReader = reader.getImageReader().getReader();
      if (log.isInfoEnabled()) {
        log.info("File format: " + format);
        log.info("Base reader: " + baseReader.getClass().getName());
      }
      notifyObservers(new ImportEvent.LOADED_IMAGE(shortName, 0, 0, 0));

      formatString = baseReader.getClass().getSimpleName();
      formatString = formatString.replace("Reader", "");

    } catch (Cancel c) {
      throw c;
    } catch (Throwable t) {
      throw helper.cancel(new ERR(), t, "error-on-init");
    } finally {
      MDC.clear();
    }
  }
コード例 #14
0
 public ReaderInvocationHandler(IFormatReader reader) {
   reader.toString(); // NPE
   this.reader = reader;
 }
コード例 #15
0
ファイル: ImageOpener.java プロジェクト: Jondeen/imglib
  /**
   * Reads in an imglib {@link Image} from the given initialized {@link IFormatReader}, using the
   * given {@link ImageFactory}.
   */
  public <T extends RealType<T>> Image<T> openImage(IFormatReader r, ImageFactory<T> imageFactory)
      throws FormatException, IOException {
    final String[] dimTypes = getDimTypes(r);
    final int[] dimLengths = getDimLengths(r);

    // TEMP - make suffix out of dimension types, until imglib supports them
    final String id = r.getCurrentFile();
    final File idFile = new File(id);
    String name = idFile.exists() ? idFile.getName() : id;
    name = encodeName(name, dimTypes);

    // create image object
    final Image<T> img = imageFactory.createImage(dimLengths, name);

    // set calibration of the image
    img.setCalibration(getCalibration(r, dimLengths));

    // TODO - create better container types; either:
    // 1) an array container type using one byte array per plane
    // 2) as #1, but with an IFormatReader reference reading planes on demand
    // 3) as PlanarContainer, but with an IFormatReader reference
    //    reading planes on demand

    // PlanarContainer is useful for efficient access to pixels in ImageJ
    // (e.g., getPixels)
    // #1 is useful for efficient Bio-Formats import, and useful for tools
    //   needing byte arrays (e.g., BufferedImage Java3D texturing by reference)
    // #2 is useful for efficient memory use for tools wanting matching
    //   primitive arrays (e.g., virtual stacks in ImageJ)
    // #3 is useful for efficient memory use

    // get container
    final PlanarAccess<?> planarAccess = getPlanarAccess(img);
    final T inputType = makeType(r.getPixelType());
    final T outputType = imageFactory.createType();
    final boolean compatibleTypes = outputType.getClass().isAssignableFrom(inputType.getClass());

    final long startTime = System.currentTimeMillis();

    // populate planes
    final int planeCount = r.getImageCount();
    if (planarAccess == null || !compatibleTypes) {
      // use cursor to populate planes

      // NB: This solution is general and works regardless of container,
      // but at the expense of performance both now and later.

      final LocalizablePlaneCursor<T> cursor = img.createLocalizablePlaneCursor();
      byte[] plane = null;
      for (int no = 0; no < planeCount; no++) {
        notifyListeners(
            new StatusEvent(no, planeCount, "Reading plane " + (no + 1) + "/" + planeCount));
        if (plane == null) plane = r.openBytes(no);
        else r.openBytes(no, plane);
        populatePlane(r, no, plane, cursor);
      }
      cursor.close();
    } else {
      // populate the values directly using PlanarAccess interface;
      // e.g., to a PlanarContainer

      byte[] plane = null;
      for (int no = 0; no < planeCount; no++) {
        notifyListeners(
            new StatusEvent(no, planeCount, "Reading plane " + (no + 1) + "/" + planeCount));
        if (plane == null) plane = r.openBytes(no);
        else r.openBytes(no, plane);
        populatePlane(r, no, plane, planarAccess);
      }
    }
    r.close();

    final long endTime = System.currentTimeMillis();
    final float time = (endTime - startTime) / 1000f;
    notifyListeners(
        new StatusEvent(
            planeCount, planeCount, id + ": read " + planeCount + " planes in " + time + "s"));

    return img;
  }
コード例 #16
0
ファイル: WrapperTest.java プロジェクト: knabar/bioformats
 @Test(dataProvider = "wrappers")
 public void testCoreMetadata(IFormatReader reader) {
   assertNotNull(reader.getCurrentFile());
   CoreMetadata[] core = reader.getCoreMetadata();
   assertEquals(core.length, reader.getSeriesCount());
   for (int i = 0; i < reader.getSeriesCount(); i++) {
     reader.setSeries(i);
     assertEquals(core[i].sizeX, reader.getSizeX());
     assertEquals(core[i].sizeY, reader.getSizeY());
     assertEquals(core[i].sizeZ, reader.getSizeZ());
     assertEquals(core[i].sizeC, reader.getSizeC());
     assertEquals(core[i].sizeT, reader.getSizeT());
     assertEquals(core[i].pixelType, reader.getPixelType());
     assertEquals(core[i].imageCount, reader.getImageCount());
     assertEquals(core[i].dimensionOrder, reader.getDimensionOrder());
     assertEquals(core[i].littleEndian, reader.isLittleEndian());
     assertEquals(core[i].rgb, reader.isRGB());
     assertEquals(core[i].interleaved, reader.isInterleaved());
     assertEquals(core[i].indexed, reader.isIndexed());
   }
 }
コード例 #17
0
  private byte[] decodeTile(int no, int row, int col) throws FormatException, IOException {
    if (tileMap[getCoreIndex()] == null) {
      return new byte[getTileSize()];
    }

    int[] zct = getZCTCoords(no);
    TileCoordinate t = new TileCoordinate(nDimensions[getCoreIndex()]);
    t.coordinate[0] = col;
    t.coordinate[1] = row;

    for (String dim : dimensionOrdering.keySet()) {
      int index = dimensionOrdering.get(dim) + 2;

      if (dim.equals("Z")) {
        t.coordinate[index] = zct[0];
      } else if (dim.equals("C")) {
        t.coordinate[index] = zct[1];
      } else if (dim.equals("T")) {
        t.coordinate[index] = zct[2];
      }
    }

    Integer index = (Integer) tileMap[getCoreIndex()].get(t);
    if (index == null) {
      return new byte[getTileSize()];
    }

    Long offset = tileOffsets[getCoreIndex()][index];
    RandomAccessInputStream ets = new RandomAccessInputStream(usedFiles[getCoreIndex()]);
    ets.seek(offset);

    CodecOptions options = new CodecOptions();
    options.interleaved = isInterleaved();
    options.littleEndian = isLittleEndian();
    int tileSize = getTileSize();
    if (tileSize == 0) {
      tileSize = tileX[getCoreIndex()] * tileY[getCoreIndex()] * 10;
    }
    options.maxBytes = (int) (offset + tileSize);

    byte[] buf = null;
    long end =
        index < tileOffsets[getCoreIndex()].length - 1
            ? tileOffsets[getCoreIndex()][index + 1]
            : ets.length();

    IFormatReader reader = null;
    String file = null;

    switch (compressionType[getCoreIndex()]) {
      case RAW:
        buf = new byte[tileSize];
        ets.read(buf);
        break;
      case JPEG:
        Codec codec = new JPEGCodec();
        buf = codec.decompress(ets, options);
        break;
      case JPEG_2000:
        codec = new JPEG2000Codec();
        buf = codec.decompress(ets, options);
        break;
      case PNG:
        file = "tile.png";
        reader = new APNGReader();
      case BMP:
        if (reader == null) {
          file = "tile.bmp";
          reader = new BMPReader();
        }

        byte[] b = new byte[(int) (end - offset)];
        ets.read(b);
        Location.mapFile(file, new ByteArrayHandle(b));
        reader.setId(file);
        buf = reader.openBytes(0);
        Location.mapFile(file, null);
        break;
    }

    if (reader != null) {
      reader.close();
    }

    ets.close();
    return buf;
  }
コード例 #18
0
  /**
   * Attempts to import the given file IDs using Bio-Formats, as a single group. Pixels are saved to
   * the pixels file designated by OMEIS, and an OME-XML metadata block describing the successfully
   * imported data is dumped to standard output.
   */
  public void importIds(int[] fileIds) throws OmeisException, FormatException, IOException {
    boolean doLittle = isLittleEndian();

    Arrays.sort(fileIds);

    // set up file path mappings
    String[] ids = new String[fileIds.length];
    for (int i = 0; i < fileIds.length; i++) {
      Hashtable fileInfo = getFileInfo(fileIds[i]);
      ids[i] = (String) fileInfo.get("Name");
      String path = getLocalFilePath(fileIds[i]);
      Location.mapId(ids[i], path);
    }

    // read file group
    String id = ids[0];
    String path = Location.getMappedId(id);
    if (DEBUG) log("Reading file '" + id + "' --> " + path);

    // verify that all given file IDs were grouped by the reader
    reader.setId(id);
    String[] used = reader.getUsedFiles();
    if (used == null) {
      throw new FormatException("Invalid file list for " + path);
    }
    if (used.length != ids.length) {
      throw new FormatException(
          "File list length mismatch for " + path + ": used=" + a2s(used) + "; ids=" + a2s(ids));
    }

    boolean[] done = new boolean[ids.length];
    int numLeft = ids.length;
    for (int i = 0; i < used.length; i++) {
      for (int j = 0; j < ids.length; j++) {
        if (done[j]) continue;
        if (used[i].equals(ids[j])) {
          done[j] = true;
          numLeft--;
          break;
        }
      }
    }
    if (numLeft > 0) {
      throw new FormatException("File list does not correspond to ID list for " + path);
    }

    int seriesCount = reader.getSeriesCount();

    // get DOM and Pixels elements for the file's OME-XML metadata
    OMENode ome = (OMENode) omexmlMeta.getRoot();
    Document omeDoc = ome.getDOMElement().getOwnerDocument();
    Vector pix = DOMUtil.findElementList("Pixels", omeDoc);
    if (pix.size() != seriesCount) {
      throw new FormatException(
          "Pixels element count ("
              + pix.size()
              + ") does not match series count ("
              + seriesCount
              + ") for '"
              + id
              + "'");
    }
    if (DEBUG) log(seriesCount + " series detected.");

    for (int s = 0; s < seriesCount; s++) {
      reader.setSeries(s);

      // gather pixels information for this series
      int sizeX = reader.getSizeX();
      int sizeY = reader.getSizeY();
      int sizeZ = reader.getSizeZ();
      int sizeC = reader.getSizeC();
      int sizeT = reader.getSizeT();
      int pixelType = reader.getPixelType();
      int bytesPerPixel;
      boolean isSigned, isFloat;
      switch (pixelType) {
        case FormatTools.INT8:
          bytesPerPixel = 1;
          isSigned = true;
          isFloat = false;
          break;
        case FormatTools.UINT8:
          bytesPerPixel = 1;
          isSigned = false;
          isFloat = false;
          break;
        case FormatTools.INT16:
          bytesPerPixel = 2;
          isSigned = true;
          isFloat = false;
          break;
        case FormatTools.UINT16:
          bytesPerPixel = 2;
          isSigned = false;
          isFloat = false;
          break;
        case FormatTools.INT32:
          bytesPerPixel = 4;
          isSigned = true;
          isFloat = false;
          break;
        case FormatTools.UINT32:
          bytesPerPixel = 4;
          isSigned = false;
          isFloat = false;
          break;
        case FormatTools.FLOAT:
          bytesPerPixel = 4;
          isSigned = true;
          isFloat = true;
          break;
        case FormatTools.DOUBLE:
          bytesPerPixel = 8;
          isSigned = true;
          isFloat = true;
          break;
        default:
          throw new FormatException(
              "Unknown pixel type for '" + id + "' series #" + s + ": " + pixelType);
      }
      boolean little = reader.isLittleEndian();
      boolean swap = doLittle != little && bytesPerPixel > 1 && !isFloat;

      // ask OMEIS to allocate new pixels file
      int pixelsId = newPixels(sizeX, sizeY, sizeZ, sizeC, sizeT, bytesPerPixel, isSigned, isFloat);
      String pixelsPath = getLocalPixelsPath(pixelsId);
      if (DEBUG) {
        log("Series #" + s + ": id=" + pixelsId + ", path=" + pixelsPath);
      }

      // write pixels to file
      FileOutputStream out = new FileOutputStream(pixelsPath);
      int imageCount = reader.getImageCount();
      if (DEBUG) {
        log(
            "Processing "
                + imageCount
                + " planes (sizeZ="
                + sizeZ
                + ", sizeC="
                + sizeC
                + ", sizeT="
                + sizeT
                + "): ");
      }
      // OMEIS expects XYZCT order --
      // interleaved RGB files will be handled a bit more slowly due to this
      // ordering (ChannelSeparator must read each plane three times), but
      // caching performed by the OS helps some
      for (int t = 0; t < sizeT; t++) {
        for (int c = 0; c < sizeC; c++) {
          for (int z = 0; z < sizeZ; z++) {
            int ndx = reader.getIndex(z, c, t);
            if (DEBUG) {
              log("Reading plane #" + ndx + ": z=" + z + ", c=" + c + ", t=" + t);
            }
            byte[] plane = reader.openBytes(ndx);
            if (swap) { // swap endianness
              for (int b = 0; b < plane.length; b += bytesPerPixel) {
                for (int k = 0; k < bytesPerPixel / 2; k++) {
                  int i1 = b + k;
                  int i2 = b + bytesPerPixel - k - 1;
                  byte b1 = plane[i1];
                  byte b2 = plane[i2];
                  plane[i1] = b2;
                  plane[i2] = b1;
                }
              }
            }
            out.write(plane);
          }
        }
      }
      out.close();
      if (DEBUG) log("[done]");

      // tell OMEIS we're done
      pixelsId = finishPixels(pixelsId);
      if (DEBUG) log("finishPixels called (new id=" + pixelsId + ")");

      // get SHA1 hash for finished pixels
      String sha1 = getPixelsSHA1(pixelsId);
      if (DEBUG) log("SHA1=" + sha1);

      // inject important extra attributes into proper Pixels element
      Element pixels = (Element) pix.elementAt(s);
      pixels.setAttribute("FileSHA1", sha1);
      pixels.setAttribute("ImageServerID", "" + pixelsId);
      pixels.setAttribute("DimensionOrder", "XYZCT"); // ignored anyway
      String pType = pixels.getAttribute("PixelType");
      if (pType.startsWith("u")) {
        pixels.setAttribute("PixelType", pType.replace('u', 'U'));
      }
      if (DEBUG) log("Pixel attributes injected.");
    }

    reader.close();

    // accumulate XML into buffer
    ByteArrayOutputStream xml = new ByteArrayOutputStream();
    try {
      DOMUtil.writeXML(xml, omeDoc);
    } catch (javax.xml.transform.TransformerException exc) {
      throw new FormatException(exc);
    }

    // output OME-XML to standard output
    xml.close();
    String xmlString = new String(xml.toByteArray());
    if (DEBUG) log(xmlString);
    if (http) printHttpResponseHeader();
    System.out.println(xmlString);
  }