@@ -425,6 +425,28 @@ typedef struct _Rtiff {
425
425
int y_pos ;
426
426
} Rtiff ;
427
427
428
+ /* Convert IEEE 754-2008 16-bit float to 32-bit float
429
+ */
430
+ static inline float
431
+ half_2_float (gushort h )
432
+ {
433
+ const float sign = (h >> 15 ) * -2 + 1 ;
434
+ const int exp = ((h & 0x7C00 ) >> 10 ) - 15 ;
435
+ const float prec = (h & 0x03FF );
436
+
437
+ switch (exp )
438
+ {
439
+ case 16 :
440
+ return INFINITY * sign ;
441
+ case -15 :
442
+ return sign / (float )(1 << 14 ) * (prec / 1024.0 );
443
+ default :
444
+ return exp > 0 ?
445
+ sign * (float )(1 << exp ) * (1.0 + prec / 1024.0 ) :
446
+ sign / (float )(1 << - exp ) * (1.0 + prec / 1024.0 );
447
+ }
448
+ }
449
+
428
450
/* Test for field exists.
429
451
*/
430
452
static int
@@ -869,6 +891,8 @@ rtiff_guess_format(Rtiff *rtiff)
869
891
return VIPS_FORMAT_SHORT ;
870
892
if (sample_format == SAMPLEFORMAT_UINT )
871
893
return VIPS_FORMAT_USHORT ;
894
+ if (sample_format == SAMPLEFORMAT_IEEEFP )
895
+ return VIPS_FORMAT_FLOAT ;
872
896
break ;
873
897
874
898
case 32 :
@@ -1229,13 +1253,37 @@ rtiff_parse_fourbit(Rtiff *rtiff, VipsImage *out)
1229
1253
} \
1230
1254
}
1231
1255
1256
+ /* GREY_LOOP implementation for 16-bit float
1257
+ */
1258
+ #define GREY_LOOP_F16 \
1259
+ { \
1260
+ gushort *p1; \
1261
+ float *q1; \
1262
+ \
1263
+ p1 = (gushort *) p; \
1264
+ q1 = (float *) q; \
1265
+ for (x = 0; x < n; x++) { \
1266
+ if (invert) \
1267
+ q1[0] = 1.0 - half_2_float(p1[0]); \
1268
+ else \
1269
+ q1[0] = half_2_float(p1[0]); \
1270
+ \
1271
+ for (i = 1; i < samples_per_pixel; i++) \
1272
+ q1[i] = half_2_float(p1[i]); \
1273
+ \
1274
+ q1 += samples_per_pixel; \
1275
+ p1 += samples_per_pixel; \
1276
+ } \
1277
+ }
1278
+
1232
1279
/* Per-scanline process function for greyscale images.
1233
1280
*/
1234
1281
static void
1235
1282
rtiff_greyscale_line (Rtiff * rtiff ,
1236
1283
VipsPel * q , VipsPel * p , int n , void * client )
1237
1284
{
1238
1285
int samples_per_pixel = rtiff -> header .samples_per_pixel ;
1286
+ int bits_per_sample = rtiff -> header .bits_per_sample ;
1239
1287
int photometric_interpretation =
1240
1288
rtiff -> header .photometric_interpretation ;
1241
1289
VipsBandFormat format = rtiff_guess_format (rtiff );
@@ -1274,7 +1322,12 @@ rtiff_greyscale_line(Rtiff *rtiff,
1274
1322
break ;
1275
1323
1276
1324
case VIPS_FORMAT_FLOAT :
1277
- GREY_LOOP (float , 1.0 );
1325
+ if (bits_per_sample == 16 ) {
1326
+ GREY_LOOP_F16 ;
1327
+ }
1328
+ else {
1329
+ GREY_LOOP (float , 1.0 );
1330
+ }
1278
1331
break ;
1279
1332
1280
1333
case VIPS_FORMAT_DOUBLE :
@@ -1565,6 +1618,28 @@ rtiff_memcpy_line(Rtiff *rtiff, VipsPel *q, VipsPel *p, int n, void *client)
1565
1618
memcpy (q , p , len );
1566
1619
}
1567
1620
1621
+ /* Per-scanline process function when we just need to copy.
1622
+ */
1623
+ static void
1624
+ rtiff_memcpy_f16_line ( Rtiff * rtiff , VipsPel * q , VipsPel * p , int n , void * client )
1625
+ {
1626
+ VipsImage * im = (VipsImage * ) client ;
1627
+ size_t len = n * im -> Bands ;
1628
+
1629
+ if ( im -> BandFmt == VIPS_FORMAT_COMPLEX ||
1630
+ im -> BandFmt == VIPS_FORMAT_DPCOMPLEX )
1631
+ len *= 2 ;
1632
+
1633
+ int i ;
1634
+
1635
+ gushort * restrict hp = (gushort * ) p ;
1636
+ float * restrict fq = (float * ) q ;
1637
+
1638
+ for ( i = 0 ; i < len ; i ++ ) {
1639
+ fq [i ] = half_2_float (hp [i ]);
1640
+ }
1641
+ }
1642
+
1568
1643
/* Read a regular multiband image where we can just copy pixels from the tiff
1569
1644
* buffer.
1570
1645
*/
@@ -1574,6 +1649,8 @@ rtiff_parse_copy(Rtiff *rtiff, VipsImage *out)
1574
1649
int samples_per_pixel = rtiff -> header .samples_per_pixel ;
1575
1650
int photometric_interpretation =
1576
1651
rtiff -> header .photometric_interpretation ;
1652
+ int bits_per_sample = rtiff -> header .bits_per_sample ;
1653
+ int sample_format = rtiff -> header .sample_format ;
1577
1654
int inkset = rtiff -> header .inkset ;
1578
1655
1579
1656
if (rtiff_non_fractional (rtiff ))
@@ -1608,16 +1685,21 @@ rtiff_parse_copy(Rtiff *rtiff, VipsImage *out)
1608
1685
else
1609
1686
out -> Type = VIPS_INTERPRETATION_MULTIBAND ;
1610
1687
1611
- rtiff -> sfn = rtiff_memcpy_line ;
1612
1688
rtiff -> client = out ;
1613
1689
1614
- /* We expand YCBCR images to RGB using JPEGCOLORMODE_RGB, and this
1615
- * means we need a slightly larger read buffer for the edge pixels. In
1616
- * turn, this means we can't just memcpy to libvips regions.
1617
- */
1618
- rtiff -> memcpy = photometric_interpretation != PHOTOMETRIC_YCBCR ;
1690
+ if ( bits_per_sample == 16 && sample_format == SAMPLEFORMAT_IEEEFP ) {
1691
+ rtiff -> sfn = rtiff_memcpy_f16_line ;
1692
+ }
1693
+ else {
1694
+ rtiff -> sfn = rtiff_memcpy_line ;
1619
1695
1620
- return 0 ;
1696
+ /* We expand YCBCR images to RGB using JPEGCOLORMODE_RGB, and this
1697
+ * means we need a slightly larger read buffer for the edge pixels. In
1698
+ * turn, this means we can't just memcpy to libvips regions.
1699
+ */
1700
+ rtiff -> memcpy = photometric_interpretation != PHOTOMETRIC_YCBCR ;
1701
+ }
1702
+ return ( 0 );
1621
1703
}
1622
1704
1623
1705
typedef int (* reader_fn )(Rtiff * rtiff , VipsImage * out );
@@ -2695,6 +2777,10 @@ rtiff_read_stripwise(Rtiff *rtiff, VipsImage *out)
2695
2777
else
2696
2778
vips_line_size = VIPS_IMAGE_SIZEOF_LINE (t [0 ]);
2697
2779
2780
+ if (rtiff -> header .bits_per_sample == 16 &&
2781
+ rtiff -> header .sample_format == SAMPLEFORMAT_IEEEFP )
2782
+ vips_line_size /= 2 ;
2783
+
2698
2784
if (vips_line_size != rtiff -> header .scanline_size ) {
2699
2785
vips_error ("tiff2vips" ,
2700
2786
"%s" , _ ("unsupported tiff image type" ));
0 commit comments