Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
95 changes: 82 additions & 13 deletions org/openslide/OpenSlide.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,17 @@
package org.openslide;

import java.awt.Color;
import java.awt.color.ColorSpace;
import java.awt.color.ICC_ColorSpace;
import java.awt.color.ICC_Profile;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
import java.awt.image.DataBuffer;
import java.awt.image.DataBufferInt;
import java.awt.image.DirectColorModel;
import java.awt.image.Raster;
import java.awt.image.WritableRaster;
import java.io.Closeable;
import java.io.File;
import java.io.FileNotFoundException;
Expand Down Expand Up @@ -113,6 +121,8 @@ public void close() throws IOException {

final private Map<String, AssociatedImage> associatedImages;

final private ColorModel colorModel;

final private File canonicalFile;

final private int hashCodeVal;
Expand Down Expand Up @@ -178,6 +188,8 @@ public OpenSlide(File file) throws IOException {

associatedImages = Collections.unmodifiableMap(associated);

colorModel = readColorModel(null);

// store info for hash and equals
canonicalFile = file.getCanonicalFile();
String quickhash1 = getProperties().get(PROPERTY_NAME_QUICKHASH1);
Expand Down Expand Up @@ -224,6 +236,10 @@ public long getLevelHeight(int level) {
return levelHeights[level];
}

public ColorModel getColorModel() {
return colorModel;
}

public void paintRegionOfLevel(Graphics2D g, int dx, int dy, int sx,
int sy, int w, int h, int level) throws IOException {
paintRegion(g, dx, dy, sx, sy, w, h, levelDownsamples[level]);
Expand All @@ -246,6 +262,14 @@ public void paintRegionARGB(int dest[], long x, long y, int level, int w,
}
}

public BufferedImage readRegion(long x, long y, int level, int w, int h)
throws IOException {
BufferedImage img = createARGBBufferedImage(colorModel, w, h);
int data[] = getARGBPixels(img);
paintRegionARGB(data, x, y, level, w, h);
return img;
}

public void paintRegion(Graphics2D g, int dx, int dy, long sx, long sy,
int w, int h, double downsample) throws IOException {
if (downsample < 1.0) {
Expand Down Expand Up @@ -288,14 +312,7 @@ public void paintRegion(Graphics2D g, int dx, int dy, long sx, long sy,
return;
}

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());
BufferedImage img = readRegion(baseX, baseY, level, levelW, levelH);

// g.scale(1.0 / relativeDS, 1.0 / relativeDS);
g.drawImage(img, dx, dy, w, h, null);
Expand Down Expand Up @@ -396,11 +413,10 @@ BufferedImage getAssociatedImage(String name) throws IOException {
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();
ColorModel cm = readColorModel(name);
BufferedImage img = createARGBBufferedImage(cm, (int) dim[0],
(int) dim[1]);
int data[] = getARGBPixels(img);

try (errorCtx) {
OpenSlideFFM.openslide_read_associated_image(errorCtx.getOsr(),
Expand Down Expand Up @@ -451,4 +467,57 @@ public boolean equals(Object obj) {

return false;
}

private static BufferedImage createARGBBufferedImage(ColorModel cm, int w,
int h) {
WritableRaster raster = Raster.createWritableRaster(
cm.createCompatibleSampleModel(w, h), null);
return new BufferedImage(cm, raster, true, null);
}

private static int[] getARGBPixels(BufferedImage img) {
DataBufferInt buf = (DataBufferInt) img.getRaster().getDataBuffer();
return buf.getData();
}

private ColorModel readColorModel(String associated) throws IOException {
ColorSpace space = readColorSpace(associated);
return new DirectColorModel(space, 32,
0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000, true,
DataBuffer.TYPE_INT);
}

private ColorSpace readColorSpace(String associated) throws IOException {
long size;
try (errorCtx) {
if (associated != null) {
size = OpenSlideFFM.openslide_get_associated_image_icc_profile_size(
errorCtx.getOsr(), associated);
} else {
size = OpenSlideFFM.openslide_get_icc_profile_size(
errorCtx.getOsr());
}
}
if (size <= 0) {
return ColorSpace.getInstance(ColorSpace.CS_sRGB);
} else if (size > Integer.MAX_VALUE) {
throw new IOException("ICC profile too large");
}

byte[] data = new byte[(int) size];
try (errorCtx) {
if (associated != null) {
OpenSlideFFM.openslide_read_associated_image_icc_profile(
errorCtx.getOsr(), associated, data);
} else {
OpenSlideFFM.openslide_read_icc_profile(errorCtx.getOsr(),
data);
}
}
try {
return new ICC_ColorSpace(ICC_Profile.getInstance(data));
} catch (IllegalArgumentException ex) {
throw new IOException("Invalid ICC profile", ex);
}
}
}
64 changes: 64 additions & 0 deletions org/openslide/OpenSlideFFM.java
Original file line number Diff line number Diff line change
Expand Up @@ -330,6 +330,32 @@ static void openslide_read_region(OpenSlideRef osr, int dest[],
}
}

private static final MethodHandle get_icc_profile_size = function(
JAVA_LONG, "openslide_get_icc_profile_size", C_POINTER);

static long openslide_get_icc_profile_size(OpenSlideRef osr) {
try (Ref.ScopedLock l = osr.lock()) {
return (long) get_icc_profile_size.invokeExact(osr.getSegment());
} catch (Throwable ex) {
throw wrapException(ex);
}
}

private static final MethodHandle read_icc_profile = function(
null, "openslide_read_icc_profile", C_POINTER, C_POINTER);

static void openslide_read_icc_profile(OpenSlideRef osr, byte dest[]) {
try (Arena arena = Arena.ofConfined()) {
MemorySegment buf = arena.allocate(JAVA_BYTE, dest.length);
try (Ref.ScopedLock l = osr.lock()) {
read_icc_profile.invokeExact(osr.getSegment(), buf);
} catch (Throwable ex) {
throw wrapException(ex);
}
MemorySegment.copy(buf, JAVA_BYTE, 0, dest, 0, dest.length);
}
}

private static final MethodHandle get_error = function(
C_POINTER, "openslide_get_error", C_POINTER);

Expand Down Expand Up @@ -438,6 +464,44 @@ static void openslide_read_associated_image(OpenSlideRef osr, String name,
}
}

private static final MethodHandle get_associated_image_icc_profile_size = function(
JAVA_LONG, "openslide_get_associated_image_icc_profile_size",
C_POINTER, C_POINTER);

static long openslide_get_associated_image_icc_profile_size(
OpenSlideRef osr, String name) {
if (name == null) {
return -1;
}
try (Arena arena = Arena.ofConfined(); Ref.ScopedLock l = osr.lock()) {
return (long) get_associated_image_icc_profile_size.invokeExact(
osr.getSegment(), arena.allocateFrom(name));
} catch (Throwable ex) {
throw wrapException(ex);
}
}

private static final MethodHandle read_associated_image_icc_profile = function(
null, "openslide_read_associated_image_icc_profile", C_POINTER,
C_POINTER, C_POINTER);

static void openslide_read_associated_image_icc_profile(OpenSlideRef osr,
String name, byte dest[]) {
if (name == null) {
return;
}
try (Arena arena = Arena.ofConfined()) {
MemorySegment buf = arena.allocate(JAVA_BYTE, dest.length);
try (Ref.ScopedLock l = osr.lock()) {
read_associated_image_icc_profile.invokeExact(osr.getSegment(),
arena.allocateFrom(name), buf);
} catch (Throwable ex) {
throw wrapException(ex);
}
MemorySegment.copy(buf, JAVA_BYTE, 0, dest, 0, dest.length);
}
}

private static final MethodHandle cache_create = function(
C_POINTER, "openslide_cache_create", SIZE_T);

Expand Down