Mercurial > octave-libtiff
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 } |