// 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(); } }
// 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(); } }
// 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(); } }
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(); } }
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; } }
public static String detectVendor(File file) { return OpenSlideJNI.openslide_detect_vendor(file.getPath()); }