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