2323package org .openslide ;
2424
2525import java .awt .Color ;
26+ import java .awt .color .ColorSpace ;
27+ import java .awt .color .ICC_ColorSpace ;
28+ import java .awt .color .ICC_Profile ;
2629import java .awt .Graphics2D ;
2730import java .awt .image .BufferedImage ;
31+ import java .awt .image .ColorModel ;
32+ import java .awt .image .DataBuffer ;
2833import java .awt .image .DataBufferInt ;
34+ import java .awt .image .DirectColorModel ;
35+ import java .awt .image .Raster ;
36+ import java .awt .image .WritableRaster ;
2937import java .io .Closeable ;
3038import java .io .File ;
3139import java .io .FileNotFoundException ;
@@ -113,6 +121,8 @@ public void close() throws IOException {
113121
114122 final private Map <String , AssociatedImage > associatedImages ;
115123
124+ final private ColorModel colorModel ;
125+
116126 final private File canonicalFile ;
117127
118128 final private int hashCodeVal ;
@@ -178,6 +188,8 @@ public OpenSlide(File file) throws IOException {
178188
179189 associatedImages = Collections .unmodifiableMap (associated );
180190
191+ colorModel = readColorModel (null );
192+
181193 // store info for hash and equals
182194 canonicalFile = file .getCanonicalFile ();
183195 String quickhash1 = getProperties ().get (PROPERTY_NAME_QUICKHASH1 );
@@ -224,6 +236,10 @@ public long getLevelHeight(int level) {
224236 return levelHeights [level ];
225237 }
226238
239+ public ColorModel getColorModel () {
240+ return colorModel ;
241+ }
242+
227243 public void paintRegionOfLevel (Graphics2D g , int dx , int dy , int sx ,
228244 int sy , int w , int h , int level ) throws IOException {
229245 paintRegion (g , dx , dy , sx , sy , w , h , levelDownsamples [level ]);
@@ -246,6 +262,14 @@ public void paintRegionARGB(int dest[], long x, long y, int level, int w,
246262 }
247263 }
248264
265+ public BufferedImage readRegion (long x , long y , int level , int w , int h )
266+ throws IOException {
267+ BufferedImage img = createARGBBufferedImage (colorModel , w , h );
268+ int data [] = getARGBPixels (img );
269+ paintRegionARGB (data , x , y , level , w , h );
270+ return img ;
271+ }
272+
249273 public void paintRegion (Graphics2D g , int dx , int dy , long sx , long sy ,
250274 int w , int h , double downsample ) throws IOException {
251275 if (downsample < 1.0 ) {
@@ -288,14 +312,7 @@ public void paintRegion(Graphics2D g, int dx, int dy, long sx, long sy,
288312 return ;
289313 }
290314
291- BufferedImage img = new BufferedImage (levelW , levelH ,
292- BufferedImage .TYPE_INT_ARGB_PRE );
293-
294- int data [] = ((DataBufferInt ) img .getRaster ().getDataBuffer ())
295- .getData ();
296-
297- paintRegionARGB (data , baseX , baseY , level , img .getWidth (), img
298- .getHeight ());
315+ BufferedImage img = readRegion (baseX , baseY , level , levelW , levelH );
299316
300317 // g.scale(1.0 / relativeDS, 1.0 / relativeDS);
301318 g .drawImage (img , dx , dy , w , h , null );
@@ -396,11 +413,10 @@ BufferedImage getAssociatedImage(String name) throws IOException {
396413 throw new IOException ("Failure reading associated image" );
397414 }
398415
399- BufferedImage img = new BufferedImage ((int ) dim [0 ], (int ) dim [1 ],
400- BufferedImage .TYPE_INT_ARGB_PRE );
401-
402- int data [] = ((DataBufferInt ) img .getRaster ().getDataBuffer ())
403- .getData ();
416+ ColorModel cm = readColorModel (name );
417+ BufferedImage img = createARGBBufferedImage (cm , (int ) dim [0 ],
418+ (int ) dim [1 ]);
419+ int data [] = getARGBPixels (img );
404420
405421 try (errorCtx ) {
406422 OpenSlideFFM .openslide_read_associated_image (errorCtx .getOsr (),
@@ -451,4 +467,57 @@ public boolean equals(Object obj) {
451467
452468 return false ;
453469 }
470+
471+ private static BufferedImage createARGBBufferedImage (ColorModel cm , int w ,
472+ int h ) {
473+ WritableRaster raster = Raster .createWritableRaster (
474+ cm .createCompatibleSampleModel (w , h ), null );
475+ return new BufferedImage (cm , raster , true , null );
476+ }
477+
478+ private static int [] getARGBPixels (BufferedImage img ) {
479+ DataBufferInt buf = (DataBufferInt ) img .getRaster ().getDataBuffer ();
480+ return buf .getData ();
481+ }
482+
483+ private ColorModel readColorModel (String associated ) throws IOException {
484+ ColorSpace space = readColorSpace (associated );
485+ return new DirectColorModel (space , 32 ,
486+ 0x00ff0000 , 0x0000ff00 , 0x000000ff , 0xff000000 , true ,
487+ DataBuffer .TYPE_INT );
488+ }
489+
490+ private ColorSpace readColorSpace (String associated ) throws IOException {
491+ long size ;
492+ try (errorCtx ) {
493+ if (associated != null ) {
494+ size = OpenSlideFFM .openslide_get_associated_image_icc_profile_size (
495+ errorCtx .getOsr (), associated );
496+ } else {
497+ size = OpenSlideFFM .openslide_get_icc_profile_size (
498+ errorCtx .getOsr ());
499+ }
500+ }
501+ if (size <= 0 ) {
502+ return ColorSpace .getInstance (ColorSpace .CS_sRGB );
503+ } else if (size > Integer .MAX_VALUE ) {
504+ throw new IOException ("ICC profile too large" );
505+ }
506+
507+ byte [] data = new byte [(int ) size ];
508+ try (errorCtx ) {
509+ if (associated != null ) {
510+ OpenSlideFFM .openslide_read_associated_image_icc_profile (
511+ errorCtx .getOsr (), associated , data );
512+ } else {
513+ OpenSlideFFM .openslide_read_icc_profile (errorCtx .getOsr (),
514+ data );
515+ }
516+ }
517+ try {
518+ return new ICC_ColorSpace (ICC_Profile .getInstance (data ));
519+ } catch (IllegalArgumentException ex ) {
520+ throw new IOException ("Invalid ICC profile" , ex );
521+ }
522+ }
454523}
0 commit comments