comparison libinterp/corefcn/__tiff__.cc @ 31168:27ed758c1688

Tiff setTag: fixed bug for rational tags and special-case tags.
author magedrifaat <magedrifaat@gmail.com>
date Fri, 12 Aug 2022 21:50:43 +0200
parents f91cd5ceaae6
children 72a159bc5a4c
comparison
equal deleted inserted replaced
31167:f91cd5ceaae6 31168:27ed758c1688
737 retval = static_cast<double> (*(reinterpret_cast<uint64_t *> (data))); 737 retval = static_cast<double> (*(reinterpret_cast<uint64_t *> (data)));
738 break; 738 break;
739 } 739 }
740 case TIFF_RATIONAL: 740 case TIFF_RATIONAL:
741 { 741 {
742 error ("TIFF_RATIONAL should have at least 2 elements but got only 1"); 742 retval = *(reinterpret_cast<float *> (data));
743 break; 743 break;
744 } 744 }
745 case TIFF_SBYTE: 745 case TIFF_SBYTE:
746 { 746 {
747 retval = static_cast<double> (*(reinterpret_cast<int8_t *> (data))); 747 retval = static_cast<double> (*(reinterpret_cast<int8_t *> (data)));
772 retval = *(reinterpret_cast<double *> (data)); 772 retval = *(reinterpret_cast<double *> (data));
773 break; 773 break;
774 } 774 }
775 case TIFF_SRATIONAL: 775 case TIFF_SRATIONAL:
776 { 776 {
777 error ("TIFF_SRATIONAL should have at least 2 elements but got only 1"); 777 retval = *(reinterpret_cast<float *> (data));
778 break; 778 break;
779 } 779 }
780 case TIFF_IFD: 780 case TIFF_IFD:
781 case TIFF_IFD8: 781 case TIFF_IFD8:
782 error ("Unimplemented IFFD data type"); 782 error ("Unimplemented IFFD data type");
852 retval = octave_value (arr); 852 retval = octave_value (arr);
853 break; 853 break;
854 } 854 }
855 case TIFF_RATIONAL: 855 case TIFF_RATIONAL:
856 { 856 {
857 // TODO(maged): This is incorrect, LibTIFF already handles
858 // rationals and converts them to floats
859 NDArray arr (arr_dims); 857 NDArray arr (arr_dims);
860 for (uint32_t i = 0; i < count; i+=2) 858 for (uint32_t i = 0; i < count; i++)
861 { 859 {
862 arr(i / 2) = static_cast<float> ((reinterpret_cast<uint32_t *> (data))[i]) 860 arr(i) = (reinterpret_cast<float *> (data))[i];
863 / static_cast<float> ((reinterpret_cast<uint32_t *> (data))[i+1]);
864 } 861 }
865 retval = octave_value (arr); 862 retval = octave_value (arr);
866 break; 863 break;
867 } 864 }
868 case TIFF_SBYTE: 865 case TIFF_SBYTE:
926 break; 923 break;
927 } 924 }
928 case TIFF_SRATIONAL: 925 case TIFF_SRATIONAL:
929 { 926 {
930 NDArray arr (arr_dims); 927 NDArray arr (arr_dims);
931 for (uint32_t i = 0; i < count; i+=2) 928 for (uint32_t i = 0; i < count; i++)
932 { 929 {
933 arr(i / 2) = static_cast<float> ((reinterpret_cast<int32_t *> (data))[i]) 930 arr(i) = (reinterpret_cast<float *> (data))[i];
934 / static_cast<float> ((reinterpret_cast<int32_t *> (data))[i+1]);
935 } 931 }
936 retval = octave_value (arr); 932 retval = octave_value (arr);
937 break; 933 break;
938 } 934 }
939 case TIFF_IFD: 935 case TIFF_IFD:
1080 &bits_per_sample)) 1076 &bits_per_sample))
1081 error ("Failed to obtain the bit depth"); 1077 error ("Failed to obtain the bit depth");
1082 1078
1083 uint32_t count = 1 << bits_per_sample; 1079 uint32_t count = 1 << bits_per_sample;
1084 uint16_t *ch1, *ch2, *ch3; 1080 uint16_t *ch1, *ch2, *ch3;
1085 if (samples_per_pixel == 1) 1081 validate_tiff_get_field (TIFFGetField (tif, tag_id,
1086 { 1082 &ch1, &ch2, &ch3));
1087 validate_tiff_get_field (TIFFGetField (tif, TIFFTAG_COLORMAP, &ch1)); 1083 if (ch2 == NULL)
1088 tag_data_ov = interpret_tag_data (ch1, count, 1084 tag_data_ov = interpret_tag_data (ch1, count,
1089 TIFFFieldDataType (fip)); 1085 TIFFFieldDataType (fip));
1090 }
1091 else 1086 else
1092 { 1087 {
1093 validate_tiff_get_field (TIFFGetField (tif, TIFFTAG_COLORMAP,
1094 &ch1, &ch2, &ch3));
1095
1096 OCTAVE_LOCAL_BUFFER (uint16NDArray, array_list, 3); 1088 OCTAVE_LOCAL_BUFFER (uint16NDArray, array_list, 3);
1097 dim_vector col_dims(count, 1); 1089 dim_vector col_dims(count, 1);
1098 array_list[0] = interpret_tag_data (ch1, 1090 array_list[0] = interpret_tag_data (ch1,
1099 count, 1091 count,
1100 TIFFFieldDataType (fip)) 1092 TIFFFieldDataType (fip))
1187 // Since scalar tags are the last to be handled, any tag that 1179 // Since scalar tags are the last to be handled, any tag that
1188 // require a count to be passed is an unsupported tag. 1180 // require a count to be passed is an unsupported tag.
1189 if (TIFFFieldPassCount (fip)) 1181 if (TIFFFieldPassCount (fip))
1190 error ("Unsupported tag"); 1182 error ("Unsupported tag");
1191 1183
1184 // According to matlab, the value must be a scalar double
1185 if (! tag_ov.is_scalar_type () || ! tag_ov.is_double_type ())
1186 error ("Tag value must be a scalar double");
1187
1192 TIFFDataType tag_datatype = TIFFFieldDataType (fip); 1188 TIFFDataType tag_datatype = TIFFFieldDataType (fip);
1193 switch (tag_datatype) 1189 switch (tag_datatype)
1194 { 1190 {
1195 case TIFF_BYTE: 1191 case TIFF_BYTE:
1196 case TIFF_UNDEFINED: 1192 case TIFF_UNDEFINED:
1197 // TODO(maged): check if matlab errors for long data type/range
1198 TIFFSetField (tif, tag_id, tag_ov.uint8_scalar_value ()); 1193 TIFFSetField (tif, tag_id, tag_ov.uint8_scalar_value ());
1199 break; 1194 break;
1200 case TIFF_ASCII: 1195 case TIFF_ASCII:
1201 TIFFSetField (tif, tag_id, tag_ov.string_value ().c_str ()); 1196 TIFFSetField (tif, tag_id, tag_ov.string_value ().c_str ());
1202 break; 1197 break;
1240 default: 1235 default:
1241 error ("Unsupported tag data type"); 1236 error ("Unsupported tag data type");
1242 } 1237 }
1243 } 1238 }
1244 1239
1240 template <typename T>
1241 void
1242 set_array_field_helper (TIFF *tif, uint32_t tag_id, T data_arr)
1243 {
1244 const void *data_ptr = data_arr.data ();
1245
1246 if (! TIFFSetField (tif, tag_id, data_ptr))
1247 error ("Failed to set tag");
1248 }
1249
1245 void 1250 void
1246 set_array_field_data (TIFF *tif, const TIFFField *fip, 1251 set_array_field_data (TIFF *tif, const TIFFField *fip,
1247 octave_value tag_ov, uint32_t count) 1252 octave_value tag_ov, uint32_t count)
1248 { 1253 {
1249 uint32_t tag_id = TIFFFieldTag (fip); 1254 uint32_t tag_id = TIFFFieldTag (fip);
1250 TIFFDataType tag_datatype = TIFFFieldDataType (fip); 1255 TIFFDataType tag_datatype = TIFFFieldDataType (fip);
1251 1256
1252 // TODO(maged): validate count? 1257 // Array type must be double in matlab
1253 octave_unused_parameter (count); 1258 if (! tag_ov.is_double_type ())
1254 1259 error ("Tag data must be double");
1255 void *data_ptr; 1260
1261 // Matlab checks number of elements not dimensions
1262 if (tag_ov.array_value ().numel () != count)
1263 error ("Expected an array with %u elements", count);
1256 1264
1257 switch (tag_datatype) 1265 switch (tag_datatype)
1258 { 1266 {
1259 case TIFF_BYTE: 1267 case TIFF_BYTE:
1260 case TIFF_UNDEFINED: 1268 case TIFF_UNDEFINED:
1261 // TODO(maged): check if matlab errors for long data type/dimensions 1269 set_array_field_helper<uint8NDArray> (tif, tag_id,
1262 // TODO(maged): should we resize/reshape? 1270 tag_ov.uint8_array_value ());
1263 data_ptr = tag_ov.uint8_array_value ().fortran_vec ();
1264 break; 1271 break;
1265 case TIFF_SHORT: 1272 case TIFF_SHORT:
1266 data_ptr = tag_ov.uint16_array_value ().fortran_vec (); 1273 set_array_field_helper<uint16NDArray> (tif, tag_id,
1274 tag_ov.uint16_array_value ());
1267 break; 1275 break;
1268 case TIFF_LONG: 1276 case TIFF_LONG:
1269 data_ptr = tag_ov.uint32_array_value ().fortran_vec (); 1277 set_array_field_helper<uint32NDArray> (tif, tag_id,
1278 tag_ov.uint32_array_value ());
1270 break; 1279 break;
1271 case TIFF_LONG8: 1280 case TIFF_LONG8:
1272 data_ptr = tag_ov.uint64_array_value ().fortran_vec (); 1281 set_array_field_helper<uint64NDArray> (tif, tag_id,
1282 tag_ov.uint64_array_value ());
1273 break; 1283 break;
1274 case TIFF_RATIONAL: 1284 case TIFF_RATIONAL:
1275 data_ptr = tag_ov.float_array_value ().fortran_vec (); 1285 set_array_field_helper<FloatNDArray> (tif, tag_id,
1286 tag_ov.float_array_value ());
1276 break; 1287 break;
1277 case TIFF_SBYTE: 1288 case TIFF_SBYTE:
1278 data_ptr = tag_ov.int8_array_value ().fortran_vec (); 1289 set_array_field_helper<int8NDArray> (tif, tag_id,
1290 tag_ov.int8_array_value ());
1279 break; 1291 break;
1280 case TIFF_SSHORT: 1292 case TIFF_SSHORT:
1281 data_ptr = tag_ov.int16_array_value ().fortran_vec (); 1293 set_array_field_helper<int16NDArray> (tif, tag_id,
1294 tag_ov.int16_array_value ());
1282 break; 1295 break;
1283 case TIFF_SLONG: 1296 case TIFF_SLONG:
1284 data_ptr = tag_ov.int32_array_value ().fortran_vec (); 1297 set_array_field_helper<int32NDArray> (tif, tag_id,
1298 tag_ov.int32_array_value ());
1285 break; 1299 break;
1286 case TIFF_SLONG8: 1300 case TIFF_SLONG8:
1287 data_ptr = tag_ov.int64_array_value ().fortran_vec (); 1301 set_array_field_helper<int64NDArray> (tif, tag_id,
1302 tag_ov.int64_array_value ());
1288 break; 1303 break;
1289 case TIFF_FLOAT: 1304 case TIFF_FLOAT:
1290 data_ptr = tag_ov.float_array_value ().fortran_vec (); 1305 set_array_field_helper<FloatNDArray> (tif, tag_id,
1306 tag_ov.float_array_value ());
1291 break; 1307 break;
1292 case TIFF_DOUBLE: 1308 case TIFF_DOUBLE:
1293 data_ptr = tag_ov.array_value ().fortran_vec (); 1309 set_array_field_helper<NDArray> (tif, tag_id,
1310 tag_ov.array_value ());
1294 break; 1311 break;
1295 case TIFF_SRATIONAL: 1312 case TIFF_SRATIONAL:
1296 data_ptr = tag_ov.float_array_value ().fortran_vec (); 1313 set_array_field_helper<FloatNDArray> (tif, tag_id,
1314 tag_ov.float_array_value ());
1297 break; 1315 break;
1298 case TIFF_IFD: 1316 case TIFF_IFD:
1299 case TIFF_IFD8: 1317 case TIFF_IFD8:
1300 error ("Unimplemented IFFD data type"); 1318 error ("Unimplemented IFFD data type");
1301 break; 1319 break;
1302 default: 1320 default:
1303 error ("Unsupported tag data type"); 1321 error ("Unsupported tag data type");
1304 } 1322 }
1305
1306 if (! TIFFSetField (tif, tag_id, data_ptr))
1307 error ("Failed to set tag");
1308 } 1323 }
1309 1324
1310 void 1325 void
1311 set_field_data (TIFF *tif, const TIFFField *fip, octave_value tag_ov) 1326 set_field_data (TIFF *tif, const TIFFField *fip, octave_value tag_ov)
1312 { 1327 {
1313 uint32_t tag_id = TIFFFieldTag (fip); 1328 uint32_t tag_id = TIFFFieldTag (fip);
1314 1329
1315 // TODO(maged): find/create images to test the special tags 1330 // TODO(maged): find/create images to test the special tags
1316 switch (tag_id) 1331 switch (tag_id)
1317 { 1332 {
1318 case TIFFTAG_YCBCRCOEFFICIENTS: 1333 case TIFFTAG_YCBCRCOEFFICIENTS:
1319 set_array_field_data (tif, fip, tag_ov, 3); 1334 set_array_field_data (tif, fip, tag_ov, 3);
1336 uint16_t bits_per_sample; 1351 uint16_t bits_per_sample;
1337 if (! TIFFGetFieldDefaulted (tif, TIFFTAG_BITSPERSAMPLE, 1352 if (! TIFFGetFieldDefaulted (tif, TIFFTAG_BITSPERSAMPLE,
1338 &bits_per_sample)) 1353 &bits_per_sample))
1339 error ("Failed to obtain the bit depth"); 1354 error ("Failed to obtain the bit depth");
1340 1355
1356 if (! tag_ov.is_double_type ())
1357 error ("Tag data must be double");
1358
1341 // According to the format specification, this field should 1359 // According to the format specification, this field should
1342 // be 8 or 16 only. 1360 // be 8 or 16 only.
1343 if (bits_per_sample > 16) 1361 if (bits_per_sample > 16)
1344 error ("Too high bit depth for a palette image"); 1362 error ("Too high bit depth for a palette image");
1345 1363
1346 // TODO(maged): what is matlab behavior for wrong input dimensions
1347 uint32_t count = 1 << bits_per_sample; 1364 uint32_t count = 1 << bits_per_sample;
1365
1366 if (tag_ov.is_scalar_type ()
1367 || tag_ov.array_value ().dim1 () != count
1368 || tag_ov.array_value ().dim2 () != 3)
1369 error ("Expected matrix with %u rows and 3 columns", count);
1370
1348 NDArray array_data = tag_ov.array_value (); 1371 NDArray array_data = tag_ov.array_value ();
1349 array_data *= UINT16_MAX; 1372 array_data *= UINT16_MAX;
1350 uint16NDArray u16_array = uint16NDArray (array_data); 1373 uint16NDArray u16_array = uint16NDArray (array_data);
1351 uint16_t *data_ptr 1374 const uint16_t *data_ptr
1352 = reinterpret_cast<uint16_t *> (u16_array.fortran_vec ()); 1375 = reinterpret_cast<const uint16_t *> (u16_array.data ());
1353 uint16_t *red = data_ptr; 1376 if (! TIFFSetField (tif, tag_id, data_ptr, data_ptr + count,
1354 uint16_t *green = red + count; 1377 data_ptr + 2 * count))
1355 uint16_t *blue = green + count;
1356 if (! TIFFSetField (tif, tag_id, red, green, blue))
1357 error ("Failed to set tag"); 1378 error ("Failed to set tag");
1358 break; 1379 break;
1359 } 1380 }
1360 case TIFFTAG_TRANSFERFUNCTION: 1381 case TIFFTAG_TRANSFERFUNCTION:
1361 { 1382 {
1369 &bits_per_sample)) 1390 &bits_per_sample))
1370 error ("Failed to obtain the bit depth"); 1391 error ("Failed to obtain the bit depth");
1371 1392
1372 uint32_t count = 1 << bits_per_sample; 1393 uint32_t count = 1 << bits_per_sample;
1373 1394
1374 uint16_t *data_ptr 1395 // An intermediate variable is required for storing the return of
1375 = reinterpret_cast<uint16_t *> (tag_ov.uint16_array_value () 1396 // uint16_array_value so that the object remains in scope and the
1376 .fortran_vec ()); 1397 // pointer returned from data () is not a dangling pointer
1398 uint16NDArray data_arr = tag_ov.uint16_array_value ();
1399
1400 if (data_arr.numel () != count)
1401 error ("Tag data should be and array of %u elements", count);
1402
1403 const uint16_t *data_ptr
1404 = reinterpret_cast<const uint16_t *> (data_arr.data ());
1377 if (samples_per_pixel == 1) 1405 if (samples_per_pixel == 1)
1378 { 1406 {
1379 if (! TIFFSetField (tif, tag_id, data_ptr)) 1407 if (! TIFFSetField (tif, tag_id, data_ptr))
1380 error ("Failed to set field"); 1408 error ("Failed to set field");
1381 } 1409 }
1390 case TIFFTAG_PAGENUMBER: 1418 case TIFFTAG_PAGENUMBER:
1391 case TIFFTAG_HALFTONEHINTS: 1419 case TIFFTAG_HALFTONEHINTS:
1392 case TIFFTAG_DOTRANGE: 1420 case TIFFTAG_DOTRANGE:
1393 case TIFFTAG_YCBCRSUBSAMPLING: 1421 case TIFFTAG_YCBCRSUBSAMPLING:
1394 { 1422 {
1395 // TODO(maged): what is matlab behavior for wrong dimensions
1396 uint16NDArray array_data = tag_ov.uint16_array_value (); 1423 uint16NDArray array_data = tag_ov.uint16_array_value ();
1424 if (array_data.numel () != 2)
1425 error ("Tag data should be an array with 2 elements");
1426
1397 if (! TIFFSetField (tif, tag_id, array_data (0), array_data (1))) 1427 if (! TIFFSetField (tif, tag_id, array_data (0), array_data (1)))
1398 error ("Failed to set field"); 1428 error ("Failed to set field");
1399 break; 1429 break;
1400 } 1430 }
1401 case TIFFTAG_SUBIFD: 1431 case TIFFTAG_SUBIFD:
1402 { 1432 {
1403 // TODO(maged): check if matlab supports setting this tag 1433 // TODO(maged): Matlab doesnt error on setting this tag
1434 // but returns 0 for getTag
1404 error ("Unsupported tag"); 1435 error ("Unsupported tag");
1405 break; 1436 break;
1406 } 1437 }
1407 case TIFFTAG_EXTRASAMPLES: 1438 case TIFFTAG_EXTRASAMPLES:
1408 { 1439 {
1409 // TODO(maged): check if matlab validates dimensions/values of this tag 1440 uint16_t samples_per_pixel;
1441 if (! TIFFGetFieldDefaulted (tif, TIFFTAG_SAMPLESPERPIXEL,
1442 &samples_per_pixel))
1443 error ("Failed to obtain the number of samples per pixel");
1444
1410 uint16NDArray data_array = tag_ov.uint16_array_value (); 1445 uint16NDArray data_array = tag_ov.uint16_array_value ();
1446 if (data_array.numel () > samples_per_pixel - 3)
1447 error ("Failed to set field, too many values");
1448
1411 if (! TIFFSetField (tif, tag_id, 1449 if (! TIFFSetField (tif, tag_id,
1412 static_cast<uint16_t> (data_array.dim1 ()), 1450 static_cast<uint16_t> (data_array.numel ()),
1413 data_array.fortran_vec ())) 1451 data_array.data ()))
1414 error ("Failed to set field"); 1452 error ("Failed to set field");
1415 break; 1453 break;
1416 } 1454 }
1417 // TODO(maged): These tags are more complex to implement 1455 // TODO(maged): These tags are more complex to implement
1418 // will be implemented and tested later. 1456 // will be implemented and tested later.
1500 perm(0) = 2; 1538 perm(0) = 2;
1501 perm(1) = 1; 1539 perm(1) = 1;
1502 perm(2) = 0; 1540 perm(2) = 0;
1503 strip_data = strip_data.permute (perm); 1541 strip_data = strip_data.permute (perm);
1504 1542
1505 void *data_vec = strip_data.fortran_vec (); 1543 uint8_t *data_u8
1544 = reinterpret_cast<uint8_t *> (strip_data.fortran_vec ());
1506 if (image_data->bits_per_sample == 8 1545 if (image_data->bits_per_sample == 8
1507 || image_data->bits_per_sample == 16 1546 || image_data->bits_per_sample == 16
1508 || image_data->bits_per_sample == 32 1547 || image_data->bits_per_sample == 32
1509 || image_data->bits_per_sample == 64) 1548 || image_data->bits_per_sample == 64)
1510 { 1549 {
1511 // Can't rely on LibTIFF's TIFFStripSize because boundary strips 1550 // Can't rely on LibTIFF's TIFFStripSize because boundary strips
1512 // can be smaller in size 1551 // can be smaller in size
1513 tsize_t strip_size = strip_data.numel () 1552 tsize_t strip_size = strip_data.numel ()
1514 * image_data->bits_per_sample / 8; 1553 * image_data->bits_per_sample / 8;
1515 if (TIFFWriteEncodedStrip (tif, strip_no, data_vec, strip_size) == -1) 1554 if (TIFFWriteEncodedStrip (tif, strip_no, data_u8, strip_size) == -1)
1516 error ("Failed to write strip data to image"); 1555 error ("Failed to write strip data to image");
1517 1556
1518 } 1557 }
1519 else if (image_data->bits_per_sample == 1) 1558 else if (image_data->bits_per_sample == 1)
1520 { 1559 {
1524 // Create a buffer to hold the packed strip data 1563 // Create a buffer to hold the packed strip data
1525 // Unique pointers are faster than vectors for constant size buffers 1564 // Unique pointers are faster than vectors for constant size buffers
1526 std::unique_ptr<uint8_t []> strip_ptr 1565 std::unique_ptr<uint8_t []> strip_ptr
1527 = std::make_unique<uint8_t []> (TIFFStripSize (tif)); 1566 = std::make_unique<uint8_t []> (TIFFStripSize (tif));
1528 uint8_t *strip_buf = strip_ptr.get (); 1567 uint8_t *strip_buf = strip_ptr.get ();
1529 uint8_t *data_u8 = reinterpret_cast<uint8_t *> (data_vec);
1530 // According to the format specification, the row should be byte 1568 // According to the format specification, the row should be byte
1531 // aligned so the number of bytes is rounded up to the nearest byte 1569 // aligned so the number of bytes is rounded up to the nearest byte
1532 uint32_t padded_width = (image_data->width + 7) / 8; 1570 uint32_t padded_width = (image_data->width + 7) / 8;
1533 // Packing the pixel data into bits 1571 // Packing the pixel data into bits
1534 for (uint32_t row = 0; row < rows_in_strip; row++) 1572 for (uint32_t row = 0; row < rows_in_strip; row++)
1602 perm(2) = 0; 1640 perm(2) = 0;
1603 tile_data = tile_data.permute (perm); 1641 tile_data = tile_data.permute (perm);
1604 1642
1605 // Octave indexing is 1-based while LibTIFF is zero-based 1643 // Octave indexing is 1-based while LibTIFF is zero-based
1606 tile_no--; 1644 tile_no--;
1607 void *data_vec = tile_data.fortran_vec (); 1645 uint8_t *data_u8 = reinterpret_cast<uint8_t *> (tile_data.fortran_vec ());
1608 if (image_data->bits_per_sample == 8 1646 if (image_data->bits_per_sample == 8
1609 || image_data->bits_per_sample == 16 1647 || image_data->bits_per_sample == 16
1610 || image_data->bits_per_sample == 32 1648 || image_data->bits_per_sample == 32
1611 || image_data->bits_per_sample == 64) 1649 || image_data->bits_per_sample == 64)
1612 { 1650 {
1613 if (TIFFWriteEncodedTile (tif, tile_no, data_vec, 1651 if (TIFFWriteEncodedTile (tif, tile_no, data_u8,
1614 TIFFTileSize (tif)) == -1) 1652 TIFFTileSize (tif)) == -1)
1615 error ("Failed to write tile data to image"); 1653 error ("Failed to write tile data to image");
1616 1654
1617 } 1655 }
1618 else if (image_data->bits_per_sample == 1) 1656 else if (image_data->bits_per_sample == 1)
1623 // Create a buffer to hold the packed tile data 1661 // Create a buffer to hold the packed tile data
1624 // Unique pointers are faster than vectors for constant size buffers 1662 // Unique pointers are faster than vectors for constant size buffers
1625 std::unique_ptr<uint8_t []> tile_ptr 1663 std::unique_ptr<uint8_t []> tile_ptr
1626 = std::make_unique<uint8_t []> (TIFFTileSize (tif)); 1664 = std::make_unique<uint8_t []> (TIFFTileSize (tif));
1627 uint8_t *tile_buf = tile_ptr.get (); 1665 uint8_t *tile_buf = tile_ptr.get ();
1628 uint8_t *data_u8 = reinterpret_cast<uint8_t *> (data_vec);
1629 // Packing the pixel data into bits 1666 // Packing the pixel data into bits
1630 for (uint32_t row = 0; row < tile_height; row++) 1667 for (uint32_t row = 0; row < tile_height; row++)
1631 { 1668 {
1632 for (uint32_t col = 0; col < tile_width; col++) 1669 for (uint32_t col = 0; col < tile_width; col++)
1633 { 1670 {
1780 1817
1781 // The default value is INT_MAX so we need to cap it to the image height 1818 // The default value is INT_MAX so we need to cap it to the image height
1782 if (row_per_strip > image_data->height) 1819 if (row_per_strip > image_data->height)
1783 row_per_strip = image_data->height; 1820 row_per_strip = image_data->height;
1784 1821
1785 uint8_t *pixel_fvec = reinterpret_cast<uint8_t *> (pixel_data.fortran_vec ()); 1822 uint8_t *pixel_fvec
1823 = reinterpret_cast<uint8_t *> (pixel_data.fortran_vec ());
1786 uint32_t strip_count = TIFFNumberOfStrips (tif); 1824 uint32_t strip_count = TIFFNumberOfStrips (tif);
1787 tsize_t strip_size; 1825 tsize_t strip_size;
1788 uint32_t rows_in_strip; 1826 uint32_t rows_in_strip;
1789 for (uint32_t strip = 0; strip < strip_count; strip++) 1827 for (uint32_t strip = 0; strip < strip_count; strip++)
1790 { 1828 {
1955 1993
1956 template <typename T> 1994 template <typename T>
1957 void 1995 void
1958 write_image (TIFF *tif, T pixel_data, tiff_image_data *image_data) 1996 write_image (TIFF *tif, T pixel_data, tiff_image_data *image_data)
1959 { 1997 {
1960 // TODO(maged): matlab sets the remaining to zero for less width and height 1998 // This dimensions checking is intentially done in this non-homogeneous
1961 // and issues a warning for larger widths but not for larger height? (we should error) 1999 // way for matlab compatibility.
1962 // and doesnt issue a warning for larger width for tiled images and produces zeros 2000 // In Matlab R2022a, If the width or height of the input matrix is less
1963 // and errors for less or more number of channels 2001 // than needed, the data is silently padded with zeroes to fit.
2002 // If the width is larger than needed, a warning is issued and the excess
2003 // data is truncated. If the height is larger than needed, no warning is
2004 // issued and the image data is wrong. If the number of channels is less
2005 // or more than needed an error is produced.
2006 // We chose to deviate from matlab in the larger height case to avoid
2007 // errors resulting from silently corrupting image data, a warning is
2008 // produced instead.
1964 if ((image_data->samples_per_pixel > 1 && pixel_data.ndims () < 3) 2009 if ((image_data->samples_per_pixel > 1 && pixel_data.ndims () < 3)
1965 || (pixel_data.ndims () > 2 2010 || (pixel_data.ndims () > 2
1966 && image_data->samples_per_pixel != pixel_data.dim3 ())) 2011 && image_data->samples_per_pixel != pixel_data.dim3 ()))
1967 error ("Incorrect number of channels, expected %u", 2012 error ("Incorrect number of channels, expected %u",
1968 image_data->samples_per_pixel); 2013 image_data->samples_per_pixel);