23
23
package org .openslide ;
24
24
25
25
import java .awt .Color ;
26
+ import java .awt .color .ColorSpace ;
27
+ import java .awt .color .ICC_ColorSpace ;
28
+ import java .awt .color .ICC_Profile ;
26
29
import java .awt .Graphics2D ;
27
30
import java .awt .image .BufferedImage ;
31
+ import java .awt .image .ColorModel ;
32
+ import java .awt .image .DataBuffer ;
28
33
import java .awt .image .DataBufferInt ;
34
+ import java .awt .image .DirectColorModel ;
35
+ import java .awt .image .Raster ;
36
+ import java .awt .image .WritableRaster ;
29
37
import java .io .Closeable ;
30
38
import java .io .File ;
31
39
import java .io .FileNotFoundException ;
@@ -113,6 +121,8 @@ public void close() throws IOException {
113
121
114
122
final private Map <String , AssociatedImage > associatedImages ;
115
123
124
+ final private ColorModel colorModel ;
125
+
116
126
final private File canonicalFile ;
117
127
118
128
final private int hashCodeVal ;
@@ -178,6 +188,8 @@ public OpenSlide(File file) throws IOException {
178
188
179
189
associatedImages = Collections .unmodifiableMap (associated );
180
190
191
+ colorModel = readColorModel (null );
192
+
181
193
// store info for hash and equals
182
194
canonicalFile = file .getCanonicalFile ();
183
195
String quickhash1 = getProperties ().get (PROPERTY_NAME_QUICKHASH1 );
@@ -224,6 +236,10 @@ public long getLevelHeight(int level) {
224
236
return levelHeights [level ];
225
237
}
226
238
239
+ public ColorModel getColorModel () {
240
+ return colorModel ;
241
+ }
242
+
227
243
public void paintRegionOfLevel (Graphics2D g , int dx , int dy , int sx ,
228
244
int sy , int w , int h , int level ) throws IOException {
229
245
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,
246
262
}
247
263
}
248
264
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
+
249
273
public void paintRegion (Graphics2D g , int dx , int dy , long sx , long sy ,
250
274
int w , int h , double downsample ) throws IOException {
251
275
if (downsample < 1.0 ) {
@@ -288,14 +312,7 @@ public void paintRegion(Graphics2D g, int dx, int dy, long sx, long sy,
288
312
return ;
289
313
}
290
314
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 );
299
316
300
317
// g.scale(1.0 / relativeDS, 1.0 / relativeDS);
301
318
g .drawImage (img , dx , dy , w , h , null );
@@ -396,11 +413,10 @@ BufferedImage getAssociatedImage(String name) throws IOException {
396
413
throw new IOException ("Failure reading associated image" );
397
414
}
398
415
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 );
404
420
405
421
try (errorCtx ) {
406
422
OpenSlideFFM .openslide_read_associated_image (errorCtx .getOsr (),
@@ -451,4 +467,57 @@ public boolean equals(Object obj) {
451
467
452
468
return false ;
453
469
}
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
+ }
454
523
}
0 commit comments