comparison libinterp/corefcn/__tiff__.cc @ 31190:a91f2f79e58c

Tiff: added internal handler for imread using the Tiff interface * __tiff__.cc (F__tiff_imread__): implemented internal function to implement imread functionality using the Tiff interface, except for the PixelRegion option.
author magedrifaat <magedrifaat@gmail.com>
date Fri, 26 Aug 2022 19:03:43 +0200
parents 6a9d985e7474
children 8ada1e68d961
comparison
equal deleted inserted replaced
31189:6a9d985e7474 31190:a91f2f79e58c
116 else 116 else
117 { 117 {
118 TIFFSetErrorHandler (NULL); 118 TIFFSetErrorHandler (NULL);
119 TIFFSetWarningHandler (NULL); 119 TIFFSetWarningHandler (NULL);
120 } 120 }
121 }
122
123 bool
124 is_numeric_scalar (octave_value ov)
125 {
126 return ov.isnumeric () && ov.isreal () && ov.is_scalar_type ();
121 } 127 }
122 128
123 // A map of tag names supported by matlab, there are some differences 129 // A map of tag names supported by matlab, there are some differences
124 // than LibTIFF's names (e.g. Photometric vs PhotometricInerpretation) 130 // than LibTIFF's names (e.g. Photometric vs PhotometricInerpretation)
125 static const std::map<std::string, ttag_t> tag_name_map = { 131 static const std::map<std::string, ttag_t> tag_name_map = {
1595 if (! TIFFGetFieldDefaulted (tif, TIFFTAG_SAMPLESPERPIXEL, 1601 if (! TIFFGetFieldDefaulted (tif, TIFFTAG_SAMPLESPERPIXEL,
1596 &samples_per_pixel)) 1602 &samples_per_pixel))
1597 error ("Failed to obtain the number of samples per pixel"); 1603 error ("Failed to obtain the number of samples per pixel");
1598 1604
1599 uint16NDArray data_array = tag_ov.uint16_array_value (); 1605 uint16NDArray data_array = tag_ov.uint16_array_value ();
1606 // FIXME: this only works for RGB images. Need to handle grayscale,
1607 // palette, cmyk and ycbcr
1600 if (data_array.numel () > samples_per_pixel - 3) 1608 if (data_array.numel () > samples_per_pixel - 3)
1601 error ("Failed to set field, too many values"); 1609 error ("Failed to set field, too many values");
1602 1610
1603 if (! TIFFSetField (tif, tag_id, 1611 if (! TIFFSetField (tif, tag_id,
1604 static_cast<uint16_t> (data_array.numel ()), 1612 static_cast<uint16_t> (data_array.numel ()),
3457 octave_tiff_handle *tiff_handle 3465 octave_tiff_handle *tiff_handle
3458 = octave_tiff_handle::get_tiff_handle (args(0)); 3466 = octave_tiff_handle::get_tiff_handle (args(0));
3459 check_closed (tiff_handle); 3467 check_closed (tiff_handle);
3460 3468
3461 set_internal_handlers (); 3469 set_internal_handlers ();
3462 3470
3463 TIFF *tif = tiff_handle->get_file (); 3471 TIFF *tif = tiff_handle->get_file ();
3464 3472
3465 if (! args(1).is_double_type () && ! args(1).is_uint32_type () 3473 if (! args(1).is_double_type () && ! args(1).is_uint32_type ()
3466 && ! args(1).is_uint64_type ()) 3474 && ! args(1).is_uint64_type ())
3467 error ("Expected offset of type double, uint32 or uint64"); 3475 error ("Expected offset of type double, uint32 or uint64");
3534 return octave_value_list(octave_scalar_map (tag_ov_map)); 3542 return octave_value_list(octave_scalar_map (tag_ov_map));
3535 #else 3543 #else
3536 err_disabled_feature ("F__tiff_make_tagid__", "Tiff"); 3544 err_disabled_feature ("F__tiff_make_tagid__", "Tiff");
3537 #endif 3545 #endif
3538 } 3546 }
3547
3548 DEFUN (__tiff_imread__, args, nargout,
3549 "Handler for imread that uses Tiff interface")
3550 {
3551 #if defined (HAVE_TIFF)
3552 int nargin = args.length ();
3553
3554 if (nargin == 0 || ! args(0).is_string ())
3555 error ("No filename provided\n");
3556
3557 uint16_t offset = 1;
3558
3559 TIFF *tif = TIFFOpen (args(0).string_value ().c_str (), "r");
3560 uint16_t dir_count = TIFFNumberOfDirectories (tif);
3561 uint16_t page = 1;
3562
3563 // Handle unpaired index parameter
3564 if (nargin > 1 && ! args(1).is_string ())
3565 {
3566 if (is_numeric_scalar (args(1)))
3567 page = args(1).uint16_scalar_value ();
3568 else
3569 error ("imread: index must be a numeric scalar");
3570 offset++;
3571 }
3572
3573 if ((nargin - offset) % 2 != 0)
3574 error ("imread: PARAM/VALUE arguments must occur in pairs");
3575
3576 // Handle all index/frames params
3577 bool found_index = false;
3578 for (uint16_t arg_idx = offset; arg_idx < nargin; arg_idx+=2)
3579 {
3580 if (! args(arg_idx).is_string ())
3581 error ("imread: PARAM in PARAM/VALUE pair must be string");
3582
3583 const char *param_cstr = args(arg_idx).string_value ().c_str ();
3584 if (strcasecmp (param_cstr, "index") == 0
3585 || strcasecmp (param_cstr, "frames") == 0)
3586 {
3587 if (found_index)
3588 error ("imread: Index or Frames may only be specified once");
3589
3590 found_index = true;
3591 octave_value val = args(arg_idx + 1);
3592 if (is_numeric_scalar (val))
3593 page = val.uint16_scalar_value ();
3594 else
3595 error ("imread: %s must be a scalar", param_cstr);
3596 }
3597 }
3598
3599 // validate frame numbers
3600 if (page < 1 || page > dir_count)
3601 error ("imread: index/frames specified are outside the number of images");
3602
3603 // Convert to zero-based indexing
3604 page = page - 1;
3605
3606 // Go to the first page
3607 if (! TIFFSetDirectory (tif, page))
3608 error ("imread: failed to read page %d", page);
3609
3610 // Obtain image info
3611 tiff_image_data image_data (tif);
3612
3613 // Set the default region
3614 uint32NDArray row_region (dim_vector (1, 3));
3615 row_region(0) = 0;
3616 row_region(1) = 1;
3617 row_region(2) = image_data.height;
3618 uint32NDArray col_region (dim_vector (1, 3));
3619 col_region(0) = 0;
3620 col_region(1) = 1;
3621 col_region(2) = image_data.width;
3622
3623 // Obtain and validate other params (pixelregion, info)
3624 for (uint16_t arg_idx = offset; arg_idx < nargin; arg_idx+=2)
3625 {
3626 if (! args(arg_idx).is_string ())
3627 error ("imread: PARAM in PARAM/VALUE pair must be string");
3628
3629 const char *param_cstr = args(arg_idx).string_value ().c_str ();
3630 if (strcasecmp (param_cstr, "index") == 0
3631 || strcasecmp (param_cstr, "frames") == 0)
3632 {
3633 // Already handled
3634 }
3635 else if (strcasecmp (param_cstr, "pixelregion") == 0)
3636 {
3637 octave_value region_ov = args(arg_idx + 1);
3638
3639 if (! region_ov.iscell () || region_ov.numel () != 2)
3640 error ("imread: %s must be a 2-element cell array", param_cstr);
3641
3642 Cell region_cell = region_ov.cell_value ();
3643 row_region = region_cell(0).floor ().uint32_array_value ();
3644 col_region = region_cell(1).floor ().uint32_array_value ();
3645
3646 if (row_region.numel () < 2 || row_region.numel () > 3
3647 || col_region.numel () < 2 || col_region.numel () > 3)
3648 error ("imread: range for %s must be a 2 or 3 element vector",
3649 param_cstr);
3650
3651 if (row_region.numel () == 2)
3652 {
3653 row_region(2) = row_region(1);
3654 row_region(1) = 1;
3655 }
3656 if (col_region.numel () == 2)
3657 {
3658 col_region(2) = col_region(1);
3659 col_region(1) = 1;
3660 }
3661
3662 if (static_cast<uint32_t> (row_region(2)) > image_data.height)
3663 error ("imread: end ROWS for PixelRegions option is larger than image height");
3664 if (static_cast<uint32_t> (col_region(2)) > image_data.width)
3665 error ("imread: end COLS for PixelRegions option is larger than image width");
3666 }
3667 else if (strcasecmp (param_cstr, "info") == 0)
3668 {
3669 // FIXME: is this useful for our use case?
3670 }
3671 else
3672 error ("imread: invalid PARAMETER '%s'", param_cstr);
3673 }
3674
3675 // Read image according to params
3676 // FIXME: this should convert YCbCr images to RGB
3677 uint16_t sample_format;
3678 TIFFGetFieldDefaulted(tif, TIFFTAG_SAMPLEFORMAT, &sample_format);
3679
3680 octave_value_list retval (3, Matrix ());
3681 switch (sample_format)
3682 {
3683 case 1:
3684 case 4:
3685 retval (0) = read_unsigned_image (tif, &image_data);
3686 break;
3687 case 2:
3688 retval (0) = read_signed_image (tif, &image_data);
3689 break;
3690 case 3:
3691 retval (0) = read_float_image (tif, &image_data);
3692 break;
3693 default:
3694 // FIXME: should this fallback to magick instead?
3695 error ("Unsupported sample format");
3696 }
3697
3698 if (nargout > 1)
3699 {
3700 // Also return the color map if available
3701 uint16_t photometric;
3702 if (TIFFGetField (tif, TIFFTAG_PHOTOMETRIC, &photometric)
3703 && photometric == PHOTOMETRIC_PALETTE)
3704 {
3705 const TIFFField *fip
3706 = TIFFFieldWithTag (tif, TIFFTAG_COLORMAP);
3707 if (fip)
3708 retval(1) = get_field_data (tif, fip);
3709 }
3710 }
3711 // FIXME: matlab returns all channels in the first argout
3712 // and doesnt separate the alpha
3713 return retval;
3714 #else
3715 err_disabled_feature ("imread", "Tiff");
3716 #endif
3717 }
3539 } 3718 }