comparison libinterp/dldfcn/__tiff__.cc @ 31146:50402b8dfb4a

Tiff: added writeEncodedTile function for writing tiled images * __tiff__.cc(F__tiff_write_encoded_tile__): added internal function for handling writeEncodedStrip. * __tiff__.cc(process_strip_or_tile): refactored common logic for strips and tiles to a function. * __tiff__.cc(write_tile): implemented logic for checking and writing tile data to image. * Tiff.m: added writeEncodedStrip method.
author magedrifaat <magedrifaat@gmail.com>
date Sun, 31 Jul 2022 18:34:59 +0200
parents 2e11f9cb30b8
children 7af78a63d3c3
comparison
equal deleted inserted replaced
31145:2e11f9cb30b8 31146:50402b8dfb4a
297 // TODO(maged): is it necessary to check FillOrder? 297 // TODO(maged): is it necessary to check FillOrder?
298 uint8_t bit_number = 7 - pixel % 8; 298 uint8_t bit_number = 7 - pixel % 8;
299 uint8_t * img_u8 = reinterpret_cast<uint8_t *> (img_fvec); 299 uint8_t * img_u8 = reinterpret_cast<uint8_t *> (img_fvec);
300 img_fvec[pixel]= (img_u8[pixel / 8] >> bit_number) & 0x01; 300 img_fvec[pixel]= (img_u8[pixel / 8] >> bit_number) & 0x01;
301 } 301 }
302 break;
303 } 302 }
304 else if (image_data->bits_per_sample == 4) 303 else if (image_data->bits_per_sample == 4)
305 { 304 {
306 if (image_data->samples_per_pixel != 1) 305 if (image_data->samples_per_pixel != 1)
307 error ("4-bit images are only supported for grayscale"); 306 error ("4-bit images are only supported for grayscale");
320 { 319 {
321 uint8_t shift = pixel % 2 == 0? 4: 0; 320 uint8_t shift = pixel % 2 == 0? 4: 0;
322 uint8_t * img_u8 = reinterpret_cast<uint8_t *> (img_fvec); 321 uint8_t * img_u8 = reinterpret_cast<uint8_t *> (img_fvec);
323 img_fvec[pixel] = (img_u8[pixel / 2] >> shift) & 0x0F; 322 img_fvec[pixel] = (img_u8[pixel / 2] >> shift) & 0x0F;
324 } 323 }
325 break;
326 } 324 }
327 else if (image_data->bits_per_sample != 8 && 325 else if (image_data->bits_per_sample != 8 &&
328 image_data->bits_per_sample != 16 && 326 image_data->bits_per_sample != 16 &&
329 image_data->bits_per_sample != 32 && 327 image_data->bits_per_sample != 32 &&
330 image_data->bits_per_sample != 64) 328 image_data->bits_per_sample != 64)
903 901
904 uint32_t strip_count = TIFFNumberOfStrips (tif); 902 uint32_t strip_count = TIFFNumberOfStrips (tif);
905 dim_vector strip_dimensions; 903 dim_vector strip_dimensions;
906 904
907 // Calculate the expected number of elements in the strip data array 905 // Calculate the expected number of elements in the strip data array
908 // All strips have equal number of rows excpet strips at the bottom 906 // All strips have equal number of rows except strips at the bottom
909 // of the image can have less number of rows 907 // of the image can have less number of rows
910 if (image_data->planar_configuration == PLANARCONFIG_CONTIG) 908 if (image_data->planar_configuration == PLANARCONFIG_CONTIG)
911 { 909 {
912 // All strips have equal number of rows excpet strips at the bottom 910 // All strips have equal number of rows excpet strips at the bottom
913 // of the image can have less number of rows 911 // of the image can have less number of rows
932 } 930 }
933 else 931 else
934 error ("Planar configuration not supported"); 932 error ("Planar configuration not supported");
935 933
936 if (strip_data.dim1 () > rows_in_strip) 934 if (strip_data.dim1 () > rows_in_strip)
937 warning ("The strip is composed of %ld rows but the input has %ld rows.", 935 warning ("The strip is composed of %u rows but the input has %ld rows.",
938 rows_in_strip, 936 rows_in_strip,
939 strip_data.dim1 ()); 937 strip_data.dim1 ());
940 938
941 if (strip_data.dim2 () > image_data->width) 939 if (strip_data.dim2 () > image_data->width)
942 warning ("The image width is %ld but the input has %ld columns.", 940 warning ("The image width is %u but the input has %ld columns.",
943 image_data->width, 941 image_data->width,
944 strip_data.dim2 ()); 942 strip_data.dim2 ());
945 943
946 if (strip_data.ndims () > 2) 944 if (strip_data.ndims () > 2)
947 { 945 {
948 if (image_data->planar_configuration == PLANARCONFIG_CONTIG 946 if (image_data->planar_configuration == PLANARCONFIG_CONTIG
949 && strip_data.dim3 () > image_data->samples_per_pixel) 947 && strip_data.dim3 () > image_data->samples_per_pixel)
950 warning ("The strip is composed of %ld channels but the input has %ld channels.", 948 warning ("The strip is composed of %u channels but the input has %ld channels.",
951 image_data->samples_per_pixel, 949 image_data->samples_per_pixel,
952 strip_data.dim3 ()); 950 strip_data.dim3 ());
953 else if (image_data->planar_configuration == PLANARCONFIG_SEPARATE 951 else if (image_data->planar_configuration == PLANARCONFIG_SEPARATE
954 && strip_data.dim3 () > 1) 952 && strip_data.dim3 () > 1)
955 warning ("The strip is composed of %ld channel but the input has %ld channels.", 953 warning ("The strip is composed of %u channel but the input has %ld channels.",
956 1, strip_data.dim3 ()); 954 1, strip_data.dim3 ());
957 } 955 }
958 956
959 // TODO(maged): check dimesnions of boundary strips in matlab 957 // TODO(maged): check dimesnions of boundary strips in matlab
960 strip_data.resize (strip_dimensions); 958 strip_data.resize (strip_dimensions);
1011 if (TIFFWriteEncodedStrip (tif, strip_no, strip_buf, strip_size) == -1) 1009 if (TIFFWriteEncodedStrip (tif, strip_no, strip_buf, strip_size) == -1)
1012 error ("Failed to write strip data to image"); 1010 error ("Failed to write strip data to image");
1013 } 1011 }
1014 else 1012 else
1015 { 1013 {
1014 error ("Unsupported bit depth");
1015 }
1016 }
1017
1018 template <typename T>
1019 void
1020 write_tile (TIFF *tif, uint32_t tile_no, T tile_data,
1021 tiff_image_data *image_data)
1022 {
1023 // TODO(maged): error for tiles not divisible by 16?
1024 uint32_t tile_width, tile_height;
1025 if (! TIFFGetField (tif, TIFFTAG_TILEWIDTH, &tile_width))
1026 error ("Failed to get the tile width");
1027 if (! TIFFGetField (tif, TIFFTAG_TILELENGTH, &tile_height))
1028 error ("Failed to get the tile length");
1029
1030 if (tile_no < 1 || tile_no > TIFFNumberOfTiles (tif))
1031 error ("Tile number out of bounds");
1032
1033 // TODO(maged): what does matlab do for boundary tiles?
1034 if (tile_data.dim1 () > tile_height)
1035 warning ("The tile is composed of %u rows but input has %ld rows",
1036 tile_height, tile_data.dim1 ());
1037 if (tile_data.dim2 () > tile_width)
1038 warning ("The tile is composed of %u columns but input has %ld columns",
1039 tile_width, tile_data.dim2 ());
1040 if (tile_data.ndims () > 2)
1041 {
1042 if (image_data->planar_configuration == PLANARCONFIG_CONTIG
1043 && tile_data.dim3 () > image_data->samples_per_pixel)
1044 warning ("The tile is composed of %u channels but input has %ld channels",
1045 image_data->samples_per_pixel, tile_data.dim3 ());
1046 else if (image_data->planar_configuration == PLANARCONFIG_SEPARATE
1047 && tile_data.dim3 () > 1)
1048 warning ("The tile is composed of %u channels but input has %ld channels",
1049 1, tile_data.dim3 ());
1050 }
1051
1052 dim_vector tile_dimensions;
1053 if (image_data->planar_configuration == PLANARCONFIG_CONTIG)
1054 tile_dimensions = dim_vector (tile_height, tile_width,
1055 image_data->samples_per_pixel);
1056 else if (image_data->planar_configuration == PLANARCONFIG_SEPARATE)
1057 tile_dimensions = dim_vector (tile_height, tile_width, 1);
1058 else
1059 error ("Planar configuration not supported");
1060
1061 tile_data.resize (tile_dimensions);
1062 Array<octave_idx_type> perm (dim_vector (3, 1));
1063 perm(0) = 2;
1064 perm(1) = 1;
1065 perm(2) = 0;
1066 tile_data = tile_data.permute (perm);
1067
1068 // Octave indexing is 1-based while LibTIFF is zero-based
1069 tile_no--;
1070 void *data_vec = tile_data.fortran_vec ();
1071 if (image_data->bits_per_sample == 8
1072 || image_data->bits_per_sample == 16
1073 || image_data->bits_per_sample == 32
1074 || image_data->bits_per_sample == 64)
1075 {
1076 if (TIFFWriteEncodedTile (tif, tile_no, data_vec,
1077 TIFFTileSize (tif)) == -1)
1078 error ("Failed to write tile data to image");
1079
1080 }
1081 else if (image_data->bits_per_sample == 1)
1082 {
1083 if (image_data->samples_per_pixel != 1)
1084 error ("Bi-Level images must have one channel only");
1085
1086 // Create a buffer to hold the packed tile data
1087 // Unique pointers are faster than vectors for constant size buffers
1088 std::unique_ptr<uint8_t []> tile_ptr
1089 = std::make_unique<uint8_t []> (TIFFTileSize (tif));
1090 uint8_t *tile_buf = tile_ptr.get ();
1091 uint8_t *data_u8 = reinterpret_cast<uint8_t *> (data_vec);
1092 // Packing the pixel data into bits
1093 for (uint32_t row = 0; row < tile_height; row++)
1094 {
1095 for (uint32_t col = 0; col < tile_width; col++)
1096 {
1097 uint8_t shift = 7 - col % 8;
1098 tile_buf[row * tile_width/8 + col/8] |= data_u8[col] << shift;
1099 }
1100 data_u8 += tile_width;
1101 }
1102 if (TIFFWriteEncodedTile (tif, tile_no, tile_buf,
1103 TIFFTileSize (tif)) == -1)
1104 error ("Failed to write tile data to image");
1105 }
1106 else
1107 {
1108 error ("Unsupported bit depth");
1109 }
1110 }
1111
1112 template <typename T>
1113 void
1114 write_strip_or_tile (TIFF *tif, uint32_t strip_tile_no, T strip_data,
1115 tiff_image_data *image_data)
1116 {
1117 if (image_data->is_tiled)
1118 write_tile<T> (tif, strip_tile_no, strip_data, image_data);
1119 else
1120 write_strip<T> (tif, strip_tile_no, strip_data, image_data);
1121 }
1122
1123 void
1124 process_strip_or_tile (TIFF *tif, uint32_t strip_tile_no,
1125 octave_value data_ov, tiff_image_data *image_data)
1126 {
1127
1128 // SampleFormat tag is not a required field and has a default value of 1
1129 // So we need to use TIFFGetFieldDefaulted in case it is not present in
1130 // the file
1131 uint16_t sample_format;
1132 if (! TIFFGetFieldDefaulted(tif, TIFFTAG_SAMPLEFORMAT, &sample_format))
1133 error ("Failed to obtain a value for sample format");
1134
1135 // TODO(maged): add support for signed integer images
1136 if (sample_format == 3)
1137 {
1138 if (image_data->bits_per_sample != 32
1139 && image_data->bits_per_sample != 64)
1140 error ("Floating point images are only supported for bit depths of 32 and 64");
1141 }
1142
1143 // The standard specifies that a SampleFormat of 4 should be treated
1144 // the same as 1 (unsigned integer)
1145 else if (sample_format != 1 && sample_format != 4)
1146 error ("Unsupported sample format");
1147
1148 switch (image_data->bits_per_sample)
1149 {
1150 case 1:
1151 // We need to check for both scalar and matrix types to handle single
1152 // element strip
1153 if (data_ov.is_bool_scalar () || data_ov.is_bool_matrix ())
1154 write_strip_or_tile<boolNDArray> (tif, strip_tile_no,
1155 data_ov.bool_array_value (),
1156 image_data);
1157 else
1158 error ("Expected logical matrix for BiLevel image");
1159 break;
1160 case 8:
1161 if (data_ov.is_uint8_type ())
1162 write_strip_or_tile<uint8NDArray> (tif, strip_tile_no,
1163 data_ov.uint8_array_value (),
1164 image_data);
1165 else
1166 error ("Only uint8 data is allowed for uint images with bit depth of 8");
1167 break;
1168 case 16:
1169 if (data_ov.is_uint16_type ())
1170 write_strip_or_tile<uint16NDArray> (tif, strip_tile_no,
1171 data_ov.uint16_array_value (),
1172 image_data);
1173 else
1174 error ("Only uint16 data is allowed for uint images with bit depth of 16");
1175 break;
1176 case 32:
1177 if (sample_format == 3)
1178 if (data_ov.is_single_type () || data_ov.is_double_type ())
1179 write_strip_or_tile<FloatNDArray> (tif, strip_tile_no,
1180 data_ov.float_array_value (),
1181 image_data);
1182 else
1183 error ("Only single and double data are allowed for floating-point images");
1184 else
1185 if (data_ov.is_uint32_type ())
1186 write_strip_or_tile<uint32NDArray> (tif, strip_tile_no,
1187 data_ov.uint32_array_value (),
1188 image_data);
1189 else
1190 error ("Only uint32 data is allowed for uint images with bit depth of 32");
1191 break;
1192 case 64:
1193 if (sample_format == 3)
1194 if (data_ov.is_single_type () || data_ov.is_double_type ())
1195 write_strip_or_tile<NDArray> (tif, strip_tile_no,
1196 data_ov.array_value (),
1197 image_data);
1198 else
1199 error ("Only single and double data are allowed for floating-point images");
1200 else
1201 if (data_ov.is_uint64_type ())
1202 write_strip_or_tile<uint64NDArray> (tif, strip_tile_no,
1203 data_ov.uint64_array_value (),
1204 image_data);
1205 else
1206 error ("Only uint64 data is allowed for uint images with bit depth of 64");
1207 break;
1208 default:
1016 error ("Unsupported bit depth"); 1209 error ("Unsupported bit depth");
1017 } 1210 }
1018 } 1211 }
1019 1212
1020 #endif 1213 #endif
1255 "Write an encoded strip to the image") 1448 "Write an encoded strip to the image")
1256 { 1449 {
1257 #if defined (HAVE_TIFF) 1450 #if defined (HAVE_TIFF)
1258 int nargin = args.length (); 1451 int nargin = args.length ();
1259 1452
1453 // TODO(maged): add support for YCbCr data
1260 if (nargin < 3) 1454 if (nargin < 3)
1261 error ("Too few arguments provided\n"); 1455 error ("Too few arguments provided\n");
1262 1456
1263 TIFF *tif = (TIFF *)(args (0).uint64_value ()); 1457 TIFF *tif = (TIFF *)(args (0).uint64_value ());
1264 1458
1274 1468
1275 uint32_t strip_no = args (1).uint32_scalar_value (); 1469 uint32_t strip_no = args (1).uint32_scalar_value ();
1276 if (strip_no < 1 || strip_no > TIFFNumberOfStrips (tif)) 1470 if (strip_no < 1 || strip_no > TIFFNumberOfStrips (tif))
1277 error ("Strip number out of range"); 1471 error ("Strip number out of range");
1278 1472
1279 // SampleFormat tag is not a required field and has a default value of 1 1473 process_strip_or_tile (tif, strip_no, args(2), &image_data);
1280 // So we need to use TIFFGetFieldDefaulted in case it is not present in
1281 // the file
1282 uint16_t sample_format;
1283 if (! TIFFGetFieldDefaulted(tif, TIFFTAG_SAMPLEFORMAT, &sample_format))
1284 error ("Failed to obtain a value for sample format");
1285
1286 // TODO(maged): add support for signed integer images
1287 if (sample_format == 3)
1288 {
1289 if (image_data.bits_per_sample != 32 && image_data.bits_per_sample != 64)
1290 error ("Floating point images are only supported for bit depths of 32 and 64");
1291 }
1292 // The standard specifies that a SampleFormat of 4 should be treated
1293 // the same as 1 (unsigned integer)
1294 else if (sample_format != 1 && sample_format != 4)
1295 error ("Unsupported sample format");
1296
1297 switch (image_data.bits_per_sample)
1298 {
1299 case 1:
1300 // We need to check for both scalar and matrix types to handle single
1301 // element strip
1302 if (args(2).is_bool_scalar () || args(2).is_bool_matrix ())
1303 write_strip<boolNDArray> (tif, strip_no,
1304 args(2).bool_array_value (), &image_data);
1305 else
1306 error ("Expected logical matrix for BiLevel image");
1307 break;
1308 case 8:
1309 if (args(2).is_uint8_type ())
1310 write_strip<uint8NDArray> (tif, strip_no,
1311 args(2).uint8_array_value (),
1312 &image_data);
1313 else
1314 error ("Only uint8 data is allowed for uint images with bit depth of 8");
1315 break;
1316 case 16:
1317 if (args(2).is_uint16_type ())
1318 write_strip<uint16NDArray> (tif, strip_no,
1319 args(2).uint16_array_value (),
1320 &image_data);
1321 else
1322 error ("Only uint16 data is allowed for uint images with bit depth of 16");
1323 break;
1324 case 32:
1325 if (sample_format == 3)
1326 if (args(2).is_single_type () || args(2).is_double_type ())
1327 write_strip<FloatNDArray> (tif, strip_no,
1328 args(2).float_array_value (),
1329 &image_data);
1330 else
1331 error ("Only single and double data are allowed for floating-point images");
1332 else
1333 if (args(2).is_uint32_type ())
1334 write_strip<uint32NDArray> (tif, strip_no,
1335 args(2).uint32_array_value (),
1336 &image_data);
1337 else
1338 error ("Only uint32 data is allowed for uint images with bit depth of 32");
1339 break;
1340 case 64:
1341 if (sample_format == 3)
1342 if (args(2).is_single_type () || args(2).is_double_type ())
1343 write_strip<NDArray> (tif, strip_no,
1344 args(2).array_value (),
1345 &image_data);
1346 else
1347 error ("Only single and double data are allowed for floating-point images");
1348 else
1349 if (args(2).is_uint64_type ())
1350 write_strip<uint64NDArray> (tif, strip_no,
1351 args(2).uint64_array_value (),
1352 &image_data);
1353 else
1354 error ("Only uint64 data is allowed for uint images with bit depth of 64");
1355 break;
1356 default:
1357 error ("Unsupported bit depth");
1358 }
1359 1474
1360 return octave_value_list (); 1475 return octave_value_list ();
1361 #else 1476 #else
1362 err_disabled_feature ("writeEncodedStrip", "Tiff"); 1477 err_disabled_feature ("writeEncodedStrip", "Tiff");
1363 #endif 1478 #endif
1364 } 1479 }
1480
1481 DEFUN_DLD (__tiff_write_encoded_tile__, args, ,
1482 "Write an encoded tile to the image")
1483 {
1484 #if defined (HAVE_TIFF)
1485 int nargin = args.length ();
1486
1487 // TODO(maged): add support for YCbCr data
1488 if (nargin < 3)
1489 error ("Too few arguments provided\n");
1490
1491 TIFF *tif = (TIFF *)(args (0).uint64_value ());
1492
1493 // TODO(maged): check on windows
1494 if (TIFFGetMode (tif) == O_RDONLY)
1495 error ("Can't write data to a file opened in read-only mode");
1496
1497 // Obtain all necessary tags
1498 tiff_image_data image_data (tif);
1499
1500 if (! image_data.is_tiled)
1501 error ("Can't write tiles to a stripped image");
1502
1503 uint32_t tile_no = args (1).uint32_scalar_value ();
1504 if (tile_no < 1 || tile_no > TIFFNumberOfTiles (tif))
1505 error ("Tile number out of range");
1506
1507 process_strip_or_tile (tif, tile_no, args(2), &image_data);
1508
1509 return octave_value_list ();
1510 #else
1511 err_disabled_feature ("writeEncodedTile", "Tiff");
1512 #endif
1513 }
1365 } 1514 }