示例#1
0
  // takes the reader lock
  BufferedImage getAssociatedImage(String name) throws IOException {
    Lock rl = lock.readLock();
    rl.lock();
    try {
      checkDisposed();

      long dim[] = new long[2];
      OpenSlideJNI.openslide_get_associated_image_dimensions(osr, name, dim);
      checkError();
      if (dim[0] == -1) {
        // non-terminal error
        throw new IOException("Failure reading associated image");
      }

      BufferedImage img =
          new BufferedImage((int) dim[0], (int) dim[1], BufferedImage.TYPE_INT_ARGB_PRE);

      int data[] = ((DataBufferInt) img.getRaster().getDataBuffer()).getData();

      OpenSlideJNI.openslide_read_associated_image(osr, name, data);
      checkError();
      return img;
    } finally {
      rl.unlock();
    }
  }
示例#2
0
  // call with the reader lock held, or from the constructor
  private void checkError() throws IOException {
    String msg = OpenSlideJNI.openslide_get_error(osr);

    if (msg != null) {
      throw new IOException(msg);
    }
  }
示例#3
0
 // takes the writer lock
 public void dispose() {
   Lock wl = lock.writeLock();
   wl.lock();
   try {
     if (osr != 0) {
       OpenSlideJNI.openslide_close(osr);
       osr = 0;
     }
   } finally {
     wl.unlock();
   }
 }
示例#4
0
  // takes the reader lock
  public void paintRegionARGB(int dest[], long x, long y, int level, int w, int h)
      throws IOException {
    if ((long) w * (long) h > dest.length) {
      throw new ArrayIndexOutOfBoundsException(
          "Size of data (" + dest.length + ") is less than w * h");
    }

    if (w < 0 || h < 0) {
      throw new IllegalArgumentException("w and h must be nonnegative");
    }

    Lock rl = lock.readLock();
    rl.lock();
    try {
      checkDisposed();
      OpenSlideJNI.openslide_read_region(osr, dest, x, y, level, w, h);
      checkError();
    } finally {
      rl.unlock();
    }
  }
示例#5
0
public final class OpenSlide implements Closeable {
  private static final FileFilter FILE_FILTER =
      new FileFilter() {
        @Override
        public boolean accept(File f) {
          return f.isDirectory() || OpenSlide.detectVendor(f) != null;
        }

        @Override
        public String getDescription() {
          return "Virtual slide";
        }
      };

  private static final String LIBRARY_VERSION = OpenSlideJNI.openslide_get_version();

  public static final String PROPERTY_NAME_COMMENT = "openslide.comment";

  public static final String PROPERTY_NAME_VENDOR = "openslide.vendor";

  public static final String PROPERTY_NAME_QUICKHASH1 = "openslide.quickhash-1";

  public static final String PROPERTY_NAME_BACKGROUND_COLOR = "openslide.background-color";

  public static final String PROPERTY_NAME_OBJECTIVE_POWER = "openslide.objective-power";

  public static final String PROPERTY_NAME_MPP_X = "openslide.mpp-x";

  public static final String PROPERTY_NAME_MPP_Y = "openslide.mpp-y";

  public static final String PROPERTY_NAME_BOUNDS_X = "openslide.bounds-x";

  public static final String PROPERTY_NAME_BOUNDS_Y = "openslide.bounds-y";

  public static final String PROPERTY_NAME_BOUNDS_WIDTH = "openslide.bounds-width";

  public static final String PROPERTY_NAME_BOUNDS_HEIGHT = "openslide.bounds-height";

  private long osr;

  private final ReadWriteLock lock = new ReentrantReadWriteLock();

  private final long levelWidths[];

  private final long levelHeights[];

  private final double levelDownsamples[];

  private final int levelCount;

  private final Map<String, String> properties;

  private final Map<String, AssociatedImage> associatedImages;

  private final File canonicalFile;

  private final int hashCodeVal;

  // vartika on 5 august
  private String filePath;

  public static String detectVendor(File file) {
    return OpenSlideJNI.openslide_detect_vendor(file.getPath());
  }

  // vartika doubt on 4 august
  // this also does not seem right..what if two people open the same file
  // maybe add requester name??
  static HashMap<String, OpenSlide> instanceArray = new HashMap<String, OpenSlide>();

  public static OpenSlide createOpenSlideInstance(String filePath) throws IOException {
    if (!instanceArray.containsKey(filePath)) {
      File file = new File(filePath);
      OpenSlide os = new OpenSlide(file);
      instanceArray.put(filePath, os);
    }
    return instanceArray.get(filePath);
  }

  public OpenSlide(File file) throws IOException {
    if (!file.exists()) {
      throw new FileNotFoundException(file.toString());
    }

    // vartika on 5 august
    filePath = file.getPath();

    osr = OpenSlideJNI.openslide_open(file.getPath());

    if (osr == 0) {
      throw new IOException(file + ": Not a file that OpenSlide can recognize");
    }
    // dispose on error, we are in the constructor
    try {
      checkError();
    } catch (IOException e) {
      dispose();
      throw e;
    }

    // store level count
    levelCount = OpenSlideJNI.openslide_get_level_count(osr);

    // store dimensions
    levelWidths = new long[levelCount];
    levelHeights = new long[levelCount];
    levelDownsamples = new double[levelCount];

    for (int i = 0; i < levelCount; i++) {
      long dim[] = new long[2];
      OpenSlideJNI.openslide_get_level_dimensions(osr, i, dim);
      levelWidths[i] = dim[0];
      levelHeights[i] = dim[1];
      levelDownsamples[i] = OpenSlideJNI.openslide_get_level_downsample(osr, i);
    }

    // properties
    HashMap<String, String> props = new HashMap<String, String>();
    for (String s : OpenSlideJNI.openslide_get_property_names(osr)) {
      props.put(s, OpenSlideJNI.openslide_get_property_value(osr, s));
    }

    properties = Collections.unmodifiableMap(props);

    // associated images
    HashMap<String, AssociatedImage> associated = new HashMap<String, AssociatedImage>();
    for (String s : OpenSlideJNI.openslide_get_associated_image_names(osr)) {
      associated.put(s, new AssociatedImage(s, this));
    }

    associatedImages = Collections.unmodifiableMap(associated);

    // store info for hash and equals
    canonicalFile = file.getCanonicalFile();
    String quickhash1 = getProperties().get(PROPERTY_NAME_QUICKHASH1);
    if (quickhash1 != null) {
      hashCodeVal = (int) Long.parseLong(quickhash1.substring(0, 8), 16);
    } else {
      hashCodeVal = canonicalFile.hashCode();
    }

    // dispose on error, we are in the constructor
    try {
      checkError();
    } catch (IOException e) {
      dispose();
      throw e;
    }
  }

  // call with the reader lock held, or from the constructor
  private void checkError() throws IOException {
    String msg = OpenSlideJNI.openslide_get_error(osr);

    if (msg != null) {
      throw new IOException(msg);
    }
  }

  // takes the writer lock
  public void dispose() {
    Lock wl = lock.writeLock();
    wl.lock();
    try {
      if (osr != 0) {
        OpenSlideJNI.openslide_close(osr);
        osr = 0;
      }
    } finally {
      wl.unlock();
    }
  }

  public int getLevelCount() {
    return levelCount;
  }

  // call with the reader lock held
  private void checkDisposed() {
    if (osr == 0) {
      throw new OpenSlideDisposedException();
    }
  }

  public long getLevel0Width() {
    return levelWidths[0];
  }

  public long getLevel0Height() {
    return levelHeights[0];
  }

  public long getLevelWidth(int level) {
    return levelWidths[level];
  }

  public long getLevelHeight(int level) {
    return levelHeights[level];
  }

  // vartika says - to change this tomorrow
  public void paintRegionOfLevel(
      Graphics2D g, int dx, int dy, int sx, int sy, int w, int h, int level) throws IOException {

    // vartika says on 3 august
    // paintRegion(g, dx, dy, sx, sy, w, h, levelDownsamples[level]);
    ReturnObject returnObject = paintRegion(sx, sy, w, h, levelDownsamples[level]);

    // vartika doubt on 3 august - shouldn't this be at client?? -who calls it?
    g.drawImage(returnObject.getImg(), dx, dy, w, h, null);

    if (debug) {
      System.out.println(returnObject.getImg());

      if (debugThingy == 0) {
        g.setColor(new Color(1.0f, 0.0f, 0.0f, 0.4f));
        debugThingy = 1;
      } else {
        g.setColor(new Color(0.0f, 1.0f, 0.0f, 0.4f));
        debugThingy = 0;
      }
      g.fillRect(dx, dy, returnObject.getW(), returnObject.getH());
    }
  }

  // takes the reader lock
  public void paintRegionARGB(int dest[], long x, long y, int level, int w, int h)
      throws IOException {
    if ((long) w * (long) h > dest.length) {
      throw new ArrayIndexOutOfBoundsException(
          "Size of data (" + dest.length + ") is less than w * h");
    }

    if (w < 0 || h < 0) {
      throw new IllegalArgumentException("w and h must be nonnegative");
    }

    Lock rl = lock.readLock();
    rl.lock();
    try {
      checkDisposed();
      OpenSlideJNI.openslide_read_region(osr, dest, x, y, level, w, h);
      checkError();
    } finally {
      rl.unlock();
    }
  }

  // vartika says on 3 august
  public ReturnObject createReturnObject(byte[] byteArray, BufferedImage img, int w, int h) {
    return new ReturnObject(byteArray, img, w, h);
  }

  // vartika says on 3 august
  // public void paintRegion(Graphics2D g, int dx, int dy, long sx, long sy,
  public ReturnObject paintRegion(long sx, long sy, int w, int h, double downsample)
      throws IOException {
    if (downsample < 1.0) {
      throw new IllegalArgumentException("downsample (" + downsample + ") must be >= 1.0");
    }

    // get the level
    int level = getBestLevelForDownsample(downsample);

    // figure out its downsample
    double levelDS = levelDownsamples[level];

    // compute the difference
    double relativeDS = downsample / levelDS;

    // scale source coordinates into level coordinates
    long baseX = (long) (downsample * sx);
    long baseY = (long) (downsample * sy);
    long levelX = (long) (relativeDS * sx);
    long levelY = (long) (relativeDS * sy);

    // scale width and height by relative downsample
    int levelW = (int) Math.round(relativeDS * w);
    int levelH = (int) Math.round(relativeDS * h);

    // clip to edge of image
    levelW = (int) Math.min(levelW, getLevelWidth(level) - levelX);
    levelH = (int) Math.min(levelH, getLevelHeight(level) - levelY);
    w = (int) Math.round(levelW / relativeDS);
    h = (int) Math.round(levelH / relativeDS);

    if (debug) {
      System.out.println(
          "levelW " + levelW + ", levelH " + levelH + ", baseX " + baseX + ", baseY " + baseY);
    }

    if (levelW <= 0 || levelH <= 0) {
      // nothing to draw
      return null;
    }

    BufferedImage img = new BufferedImage(levelW, levelH, BufferedImage.TYPE_INT_ARGB_PRE);

    int data[] = ((DataBufferInt) img.getRaster().getDataBuffer()).getData();

    paintRegionARGB(data, baseX, baseY, level, img.getWidth(), img.getHeight());

    // vartika says on 5 august
    System.out.println("data in paintRegion: " + data);
    System.out.println("img in paintRegion: " + img);

    // from here return the buffered image to client for drawing
    // below code should be at client
    // vartika says on 2 august
    // g.scale(1.0 / relativeDS, 1.0 / relativeDS);

    // vartika on 6 august
    // trying to convert int data[] to byte [] or String...
    ByteBuffer byteBuffer = ByteBuffer.allocate(data.length * 4);
    IntBuffer intBuffer = byteBuffer.asIntBuffer();
    intBuffer.put(data);
    byte[] byteArray = byteBuffer.array();

    // vartika on 10 august
    // saving buffered image to disk as png
    // try {
    // vartika on 13 august to for demo
    // File outputFile = new File("/home/vartika/humintec/image_files/BufferedImageToPng.png");
    //  ImageIO.write(img, "png", outputFile);

    // } catch(IOException e) {
    //   e.printStackTrace();
    // }

    // instead of using int[]data to create bytearray, use the buffered image to create byte []
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    ImageIO.write(img, "png", baos);
    baos.flush();
    byte[] byteArrayFromBufferedImage = baos.toByteArray();
    baos.close();
    ReturnObject tmpobj = createReturnObject(byteArrayFromBufferedImage, img, w, h);
    return tmpobj;

    // vartika to uncomment later - 10 august
    // vartika says on 3 august
    /*ReturnObject obj = createReturnObject(byteArray, img, w, h);
    return obj;*/

    /* g.drawImage(img, dx, dy, w, h, null);

    if (debug) {
        System.out.println(img);

        if (debugThingy == 0) {
            g.setColor(new Color(1.0f, 0.0f, 0.0f, 0.4f));
            debugThingy = 1;
        } else {
            g.setColor(new Color(0.0f, 1.0f, 0.0f, 0.4f));
            debugThingy = 0;
        }
        g.fillRect(dx, dy, w, h);
    }*/
  }

  final boolean debug = false;

  private int debugThingy = 0;

  public BufferedImage createThumbnailImage(
      int x, int y, long w, long h, int maxSize, int bufferedImageType) throws IOException {
    double ds;

    if (w > h) {
      ds = (double) w / maxSize;
    } else {
      ds = (double) h / maxSize;
    }

    if (ds < 1.0) {
      ds = 1.0;
    }

    int sw = (int) (w / ds);
    int sh = (int) (h / ds);
    int sx = (int) (x / ds);
    int sy = (int) (y / ds);

    BufferedImage result = new BufferedImage(sw, sh, bufferedImageType);

    Graphics2D g = result.createGraphics();

    // vartika says on 3 august
    // vartika doubt on 3 august - where is this draw being called from? need to move it to client

    ReturnObject returnObject = paintRegion(sx, sy, sw, sh, ds);
    g.drawImage(returnObject.getImg(), 0, 0, returnObject.getW(), returnObject.getH(), null);

    if (debug) {
      System.out.println(returnObject.getImg());

      if (debugThingy == 0) {
        g.setColor(new Color(1.0f, 0.0f, 0.0f, 0.4f));
        debugThingy = 1;
      } else {
        g.setColor(new Color(0.0f, 1.0f, 0.0f, 0.4f));
        debugThingy = 0;
      }
      g.fillRect(0, 0, returnObject.getW(), returnObject.getH());
    }

    g.dispose();
    return result;
  }

  public BufferedImage createThumbnailImage(int x, int y, long w, long h, int maxSize)
      throws IOException {
    return createThumbnailImage(x, y, w, h, maxSize, BufferedImage.TYPE_INT_RGB);
  }

  public BufferedImage createThumbnailImage(int maxSize) throws IOException {
    return createThumbnailImage(0, 0, getLevel0Width(), getLevel0Height(), maxSize);
  }

  public double getLevelDownsample(int level) {
    return levelDownsamples[level];
  }

  public int getBestLevelForDownsample(double downsample) {
    // too small, return first
    if (downsample < levelDownsamples[0]) {
      return 0;
    }

    // find where we are in the middle
    for (int i = 1; i < levelCount; i++) {
      if (downsample < levelDownsamples[i]) {
        return i - 1;
      }
    }

    // too big, return last
    return levelCount - 1;
  }

  public Map<String, String> getProperties() {
    return properties;
  }

  public Map<String, AssociatedImage> getAssociatedImages() {
    return associatedImages;
  }

  // takes the reader lock
  BufferedImage getAssociatedImage(String name) throws IOException {
    Lock rl = lock.readLock();
    rl.lock();
    try {
      checkDisposed();

      long dim[] = new long[2];
      OpenSlideJNI.openslide_get_associated_image_dimensions(osr, name, dim);
      checkError();
      if (dim[0] == -1) {
        // non-terminal error
        throw new IOException("Failure reading associated image");
      }

      BufferedImage img =
          new BufferedImage((int) dim[0], (int) dim[1], BufferedImage.TYPE_INT_ARGB_PRE);

      int data[] = ((DataBufferInt) img.getRaster().getDataBuffer()).getData();

      OpenSlideJNI.openslide_read_associated_image(osr, name, data);
      checkError();
      return img;
    } finally {
      rl.unlock();
    }
  }

  public static String getLibraryVersion() {
    return LIBRARY_VERSION;
  }

  public static FileFilter getFileFilter() {
    return FILE_FILTER;
  }

  @Override
  public int hashCode() {
    return hashCodeVal;
  }

  @Override
  public boolean equals(Object obj) {
    if (obj == this) {
      return true;
    }

    if (obj instanceof OpenSlide) {
      OpenSlide os2 = (OpenSlide) obj;
      String quickhash1 = getProperties().get(PROPERTY_NAME_QUICKHASH1);
      String os2_quickhash1 = os2.getProperties().get(PROPERTY_NAME_QUICKHASH1);

      if (quickhash1 != null && os2_quickhash1 != null) {
        return quickhash1.equals(os2_quickhash1);
      } else if (quickhash1 == null && os2_quickhash1 == null) {
        return canonicalFile.equals(os2.canonicalFile);
      } else {
        return false;
      }
    }

    return false;
  }

  @Override
  public void close() {
    dispose();
  }
}
示例#6
0
  public OpenSlide(File file) throws IOException {
    if (!file.exists()) {
      throw new FileNotFoundException(file.toString());
    }

    // vartika on 5 august
    filePath = file.getPath();

    osr = OpenSlideJNI.openslide_open(file.getPath());

    if (osr == 0) {
      throw new IOException(file + ": Not a file that OpenSlide can recognize");
    }
    // dispose on error, we are in the constructor
    try {
      checkError();
    } catch (IOException e) {
      dispose();
      throw e;
    }

    // store level count
    levelCount = OpenSlideJNI.openslide_get_level_count(osr);

    // store dimensions
    levelWidths = new long[levelCount];
    levelHeights = new long[levelCount];
    levelDownsamples = new double[levelCount];

    for (int i = 0; i < levelCount; i++) {
      long dim[] = new long[2];
      OpenSlideJNI.openslide_get_level_dimensions(osr, i, dim);
      levelWidths[i] = dim[0];
      levelHeights[i] = dim[1];
      levelDownsamples[i] = OpenSlideJNI.openslide_get_level_downsample(osr, i);
    }

    // properties
    HashMap<String, String> props = new HashMap<String, String>();
    for (String s : OpenSlideJNI.openslide_get_property_names(osr)) {
      props.put(s, OpenSlideJNI.openslide_get_property_value(osr, s));
    }

    properties = Collections.unmodifiableMap(props);

    // associated images
    HashMap<String, AssociatedImage> associated = new HashMap<String, AssociatedImage>();
    for (String s : OpenSlideJNI.openslide_get_associated_image_names(osr)) {
      associated.put(s, new AssociatedImage(s, this));
    }

    associatedImages = Collections.unmodifiableMap(associated);

    // store info for hash and equals
    canonicalFile = file.getCanonicalFile();
    String quickhash1 = getProperties().get(PROPERTY_NAME_QUICKHASH1);
    if (quickhash1 != null) {
      hashCodeVal = (int) Long.parseLong(quickhash1.substring(0, 8), 16);
    } else {
      hashCodeVal = canonicalFile.hashCode();
    }

    // dispose on error, we are in the constructor
    try {
      checkError();
    } catch (IOException e) {
      dispose();
      throw e;
    }
  }
示例#7
0
 public static String detectVendor(File file) {
   return OpenSlideJNI.openslide_detect_vendor(file.getPath());
 }