Mercurial > octave-libtiff
changeset 31109:06814e8b5a29
add function to read an entire image
* __tiff__.cc (F__tiff_read__): Implemented a simple layer to read
stripped images using libtiff TIFFReadEncodedStrip API, implementation
is still buggy.
* Tiff.m: added read method to reference the new internal function.
author | magedrifaat <magedrifaat@gmail.com> |
---|---|
date | Wed, 06 Jul 2022 04:44:17 +0200 |
parents | 99a301eb315e |
children | 2daeeff33980 |
files | libinterp/dldfcn/__tiff__.cc scripts/io/Tiff.m |
diffstat | 2 files changed, 203 insertions(+), 35 deletions(-) [+] |
line wrap: on
line diff
--- a/libinterp/dldfcn/__tiff__.cc Tue Jul 05 04:11:37 2022 +0200 +++ b/libinterp/dldfcn/__tiff__.cc Wed Jul 06 04:44:17 2022 +0200 @@ -34,7 +34,7 @@ } octave_value_list - interpret_scalar(void *data, TIFFDataType tag_datatype) + interpret_scalar (void *data, TIFFDataType tag_datatype) { double retval; @@ -109,7 +109,7 @@ error ("Unsupported tag data type"); } - return octave_value_list(octave_value(retval)); + return octave_value_list (octave_value (retval)); } // Convert memory buffer into suitable octave values @@ -143,7 +143,7 @@ } case TIFF_ASCII: { - ovl_data(0) = octave_value(*(char **)data); + ovl_data(0) = octave_value (*(char **)data); break; } case TIFF_SHORT: @@ -456,7 +456,7 @@ #endif DEFUN_DLD (__open_tiff__, args, nargout, - "Open a Tiff file and return its handle") + "Open a Tiff file and return its handle") { #if defined (HAVE_TIFF) int nargin = args.length (); @@ -490,7 +490,7 @@ DEFUN_DLD (__close_tiff__, args, nargout, - "Close a tiff file") + "Close a tiff file") { #if defined (HAVE_TIFF) int nargin = args.length (); @@ -509,45 +509,212 @@ DEFUN_DLD (__tiff_get_tag__, args, nargout, - "Get the value of a tag from a tiff image") + "Get the value of a tag from a tiff image") { #if defined (HAVE_TIFF) - int nargin = args.length (); + int nargin = args.length (); - if (nargin == 0) - error ("No handle provided\n"); - - if (nargin < 2) - error ("No tag name provided\n"); - - TIFF *tif = (TIFF *)(args (0).uint64_value ()); + if (nargin == 0) + error ("No handle provided\n"); + + if (nargin < 2) + error ("No tag name provided\n"); + + TIFF *tif = (TIFF *)(args (0).uint64_value ()); - uint32_t tag_id; - const TIFFField *fip; - if (args (1).type_name () == "string") - { - std::string tagName = args (1).string_value (); - fip = TIFFFieldWithName (tif, tagName.c_str ()); - if (! fip) - error ("Tiff tag not found"); - - tag_id = TIFFFieldTag (fip); - } - else - { - tag_id = args (1).int_value (); - fip = TIFFFieldWithTag (tif, tag_id); - // TODO(maged): Handle other types of errors (e.g. unsupported tags) - if (! fip) - error ("Tiff tag not found"); - } + uint32_t tag_id; + const TIFFField *fip; + if (args (1).type_name () == "string") + { + std::string tagName = args (1).string_value (); + fip = TIFFFieldWithName (tif, tagName.c_str ()); + if (! fip) + error ("Tiff tag not found"); + + tag_id = TIFFFieldTag (fip); + } + else + { + tag_id = args (1).int_value (); + fip = TIFFFieldWithTag (tif, tag_id); + // TODO(maged): Handle other types of errors (e.g. unsupported tags) + if (! fip) + error ("Tiff tag not found"); + } - octave_value_list tag_data_ovl = get_field_data (tif, fip); + octave_value_list tag_data_ovl = get_field_data (tif, fip); - return tag_data_ovl; + return tag_data_ovl; #else err_disabled_feature ("getTag", "Tiff"); #endif } + + DEFUN_DLD (__tiff_read__, args, nargout, + "Read the image in the current IFD") + { +#if defined (HAVE_TIFF) + int nargin = args.length (); + + if (nargin == 0) + error ("No handle provided\n"); + + TIFF *tif = (TIFF *)(args (0).uint64_value ()); + + // Check: Strips vs Tiles + // Planar Configuration + // StripByteCounts + // SamplesPerPixel and bits_per_smaple + // nargout and ycbcr + // ExtendedSamples? TransferFunction? GrayResponse? ColorMap? + // What about floating point images? + + // Obtain all necessary tags + uint32_t width, height; + if (! TIFFGetField (tif, TIFFTAG_IMAGEWIDTH, &width)) + error ("Failed to read image width"); + + if (! TIFFGetField (tif, TIFFTAG_IMAGELENGTH, &height)) + error ("Failed to read image height"); + + uint16_t samples_per_pixel; + if (! TIFFGetField (tif, TIFFTAG_SAMPLESPERPIXEL, &samples_per_pixel)) + error ("Failed to read the SamplesPerPixel tag"); + + uint16_t bits_per_sample; + if (! TIFFGetField (tif, TIFFTAG_BITSPERSAMPLE, &bits_per_sample)) + error ("Failed to read the BitsPerSample tag"); + + uint16_t planar_configuration; + if (! TIFFGetField (tif, TIFFTAG_PLANARCONFIG, &planar_configuration)) + error ("Failed to read the PlanarConfiguration tag"); + + uint16_t is_tiled = TIFFIsTiled(tif); + + // Create memory for storing the image data + // TODO(maged): replace malloc with a suitable C++ structure + void ***image = (void ***)malloc (sizeof(void ***) * height); + uint32_t pixel_size = samples_per_pixel * (bits_per_sample / 8); + uint32_t row_size = width * pixel_size; + for (uint32_t row = 0; row < height; row++) + { + image[row] = (void **)malloc (sizeof(void **) * width); + for (uint32_t column = 0; column < width; column++) + image[row][column] = malloc (pixel_size); + } + + if (is_tiled) + // TODO(maged): Implement tiled images + error ("Tiled images are not implemented yet"); + else + { + // Obtain the necessary data for handling the strips + uint32_t strip_count = TIFFNumberOfStrips (tif); + uint32_t *strip_byte_counts; + if (! TIFFGetField (tif, TIFFTAG_STRIPBYTECOUNTS, &strip_byte_counts)) + error ("Failed to read StripByteCounts tag"); + + uint32_t strip_size = strip_byte_counts[0]; + tdata_t buf = _TIFFmalloc (strip_size); + uint32_t row_index = 0; + for (uint32_t strip = 0; strip < strip_count; strip++) + { + if (strip_size < strip_byte_counts[strip]) + { + buf = _TIFFrealloc (buf, strip_byte_counts[strip]); + strip_size = strip_byte_counts[strip]; + } + TIFFReadEncodedStrip (tif, strip, buf, -1); + if (planar_configuration == PLANARCONFIG_CONTIG) + { + uint32_t rows_in_strip = strip_byte_counts[strip] / row_size; + for (uint32_t row_subindex = 0; + row_subindex < rows_in_strip; + row_subindex++) + { + for (uint32_t column = 0; column < width; column++) + memcpy (image[row_index + row_subindex][column], + buf + row_size * row_subindex + + column * pixel_size, pixel_size); + } + row_index += rows_in_strip; + } + else + error ("Images with multiple planes are not implemented yet"); + } + _TIFFfree (buf); + } + + octave_value_list retval; + dim_vector arr_dims (height, width, samples_per_pixel); + // TODO(maged): what about palette images? are they handled internally? + switch (bits_per_sample) + { + // TODO(maged): this is probably incorrect as bilevel has no BitsPerSample + case 1: + { + boolNDArray arr(arr_dims); + for (uint32_t row = 0; row < height; row++) + for (uint32_t column = 0; column < width; column++) + for (uint16_t sample = 0; sample < samples_per_pixel; sample++) + arr(row, column, sample) = ((uint8_t ***)image)[row][column][sample]; + + retval(0) = arr; + break; + } + // TODO(maged): bits_per_sample of 4 will probably require more logic + case 4: + case 8: + { + uint8NDArray arr(arr_dims); + for (uint32_t row = 0; row < height; row++) + for (uint32_t column = 0; column < width; column++) + for (uint16_t sample = 0; sample < samples_per_pixel; sample++) + arr(row, column, sample) = ((uint8_t ***)image)[row][column][sample]; + + retval(0) = arr; + break; + } + case 16: + { + uint16NDArray arr(arr_dims); + for (uint32_t row = 0; row < height; row++) + for (uint32_t column = 0; column < width; column++) + for (uint16_t sample = 0; sample < samples_per_pixel; sample++) + arr(row, column, sample) = ((uint16_t ***)image)[row][column][sample]; + + retval(0) = arr; + break; + } + case 32: + { + uint32NDArray arr(arr_dims); + for (uint32_t row = 0; row < height; row++) + for (uint32_t column = 0; column < width; column++) + for (uint16_t sample = 0; sample < samples_per_pixel; sample++) + arr(row, column, sample) = ((uint32_t ***)image)[row][column][sample]; + + retval(0) = arr; + break; + } + case 64: + { + uint64NDArray arr(arr_dims); + for (uint32_t row = 0; row < height; row++) + for (uint32_t column = 0; column < width; column++) + for (uint16_t sample = 0; sample < samples_per_pixel; sample++) + arr(row, column, sample) = ((uint64_t ***)image)[row][column][sample]; + + retval(0) = arr; + break; + } + default: + error ("Unsupported bit depth"); + } + return retval; +#else + err_disabled_feature ("read", "Tiff"); +#endif + } }