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;
  }
Esempio n. 2
0
  /**
   * 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;
  }
  /**
   * 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);
  }