Mercurial > octave-libtiff
view libinterp/dldfcn/__tiff__.cc @ 31103:76b21bed2920
Undocumented and unimplemented tags are explicilty mentioned and handled
* __tiff__.cc: Comlpex unimplemented tags now give an error message
and tags that are undocumented are explicitly mentioned.
author | magedrifaat <magedrifaat@gmail.com> |
---|---|
date | Sun, 03 Jul 2022 22:51:08 +0200 |
parents | d6ecf0e8838b |
children | b5d59c115e52 |
line wrap: on
line source
#include <string> #include <iostream> #include "defun-dld.h" #include "ov.h" #include "ovl.h" #include "error.h" #include <tiffio.h> // TODO(maged): Tidy up the formatting to be consistant with octave namespace octve { // Error if status is not 1 (success status for TIFFGetField) void validate_tiff_get_field (bool status, void *p_to_free=NULL) { if (status != 1) { if (p_to_free != NULL) _TIFFfree (p_to_free); error ("Failed to read tag"); } } // Convert memory buffer into suitable octave values // depending on tag_datatype octave_value_list interpret_data (void *data, uint32_t count, TIFFDataType tag_datatype) { // TODO(maged): Find the correct way fo returning multivalues octave_value_list ovl_data; dim_vector arr_dims (1, count); switch (tag_datatype) { case TIFF_BYTE: case TIFF_UNDEFINED: { uint8NDArray arr (arr_dims); for (uint32_t i = 0; i < count; i++) { arr(i) = ((uint8_t *)data)[i]; } ovl_data(0) = arr; break; } case TIFF_ASCII: { ovl_data(0) = *(char **)data; break; } case TIFF_SHORT: { uint16NDArray arr (arr_dims); for (uint32_t i = 0; i < count; i++) { arr(i) = ((uint16_t *)data)[i]; } ovl_data(0) = arr; break; } case TIFF_LONG: { uint32NDArray arr (arr_dims); for (uint32_t i = 0; i < count; i++) { arr(i) = ((uint32_t *)data)[i]; } ovl_data(0) = arr; break; } case TIFF_LONG8: { uint64NDArray arr (arr_dims); for (uint32_t i = 0; i < count; i++) { arr(i) = ((uint64_t *)data)[i]; } ovl_data(0) = arr; break; } case TIFF_RATIONAL: { NDArray arr (arr_dims); for (uint32_t i = 0; i < count; i+=2) { arr(i / 2) = (float)((uint32_t *)data)[i] / (float)((uint32_t *)data)[i+1]; } ovl_data(0) = arr; break; } case TIFF_SBYTE: { int8NDArray arr (arr_dims); for (uint32_t i = 0; i < count; i++) { arr(i) = ((int8_t *)data)[i]; } ovl_data(0) = arr; break; } case TIFF_SSHORT: { int16NDArray arr (arr_dims); for (uint32_t i = 0; i < count; i++) { arr(i) = ((int16_t *)data)[i]; } ovl_data(0) = arr; break; } case TIFF_SLONG: { int32NDArray arr (arr_dims); for (uint32_t i = 0; i < count; i++) { arr(i) = ((int32_t *)data)[i]; } ovl_data(0) = arr; break; } case TIFF_SLONG8: { int64NDArray arr (arr_dims); for (uint32_t i = 0; i < count; i++) { arr(i) = ((int64_t *)data)[i]; } ovl_data(0) = arr; break; } case TIFF_FLOAT: { NDArray arr (arr_dims); for (uint32_t i = 0; i < count; i++) { arr(i) = ((float *)data)[i]; } ovl_data(0) = arr; break; } case TIFF_DOUBLE: { NDArray arr (arr_dims); for (uint32_t i = 0; i < count; i++) { arr(i) = ((double *)data)[i]; } ovl_data(0) = arr; break; } case TIFF_SRATIONAL: { NDArray arr (arr_dims); for (uint32_t i = 0; i < count; i+=2) { arr(i / 2) = (float)((int32_t *)data)[i] / (float)((int32_t *)data)[i+1]; } ovl_data(0) = arr; break; } case TIFF_IFD: case TIFF_IFD8: // TODO(maged): implement IFD datatype? error ("Unimplemented IFFD data type"); break; default: error ("Unsupported tag data type"); } return ovl_data; } octave_value_list get_scalar_field_data (TIFF *tif, const TIFFField *fip) { octave_value_list tag_data_ovl; uint32_t tag_id = TIFFFieldTag (fip); // TIFFFieldReadCount returns VARIABLE for some scalar tags // (e.g. Compression) But TIFFFieldPassCount seems consistent // Since scalar tags are the last to be handled, any tag that // require a count to be passed is an unsupported tag. if (TIFFFieldPassCount (fip)) error ("Unsupported tag"); // TODO(maged): test this function vs actual data type size int type_size = TIFFDataWidth (TIFFFieldDataType (fip)); void *data = _TIFFmalloc (type_size); validate_tiff_get_field (TIFFGetField (tif, tag_id, data), data); tag_data_ovl = interpret_data (data, 1, TIFFFieldDataType (fip)); _TIFFfree (data); return tag_data_ovl; } octave_value_list get_array_field_data (TIFF *tif, const TIFFField *fip, uint32_t array_size) { void *data; validate_tiff_get_field (TIFFGetField (tif, TIFFFieldTag (fip), &data)); return interpret_data (data, array_size, TIFFFieldDataType (fip)); } octave_value_list get_field_data (TIFF *tif, const TIFFField *fip) { octave_value_list tag_data_ovl; uint32_t tag_id = TIFFFieldTag (fip); // TODO(maged): find/create images to test the special tags switch (tag_id) { case TIFFTAG_STRIPBYTECOUNTS: case TIFFTAG_STRIPOFFSETS: tag_data_ovl = get_array_field_data (tif, fip, TIFFNumberOfStrips (tif)); break; case TIFFTAG_TILEBYTECOUNTS: case TIFFTAG_TILEOFFSETS: tag_data_ovl = get_array_field_data (tif, fip, TIFFNumberOfTiles (tif)); break; case TIFFTAG_YCBCRCOEFFICIENTS: tag_data_ovl = get_array_field_data (tif, fip, 3); break; case TIFFTAG_REFERENCEBLACKWHITE: tag_data_ovl = get_array_field_data (tif, fip, 6); break; case TIFFTAG_COLORMAP: { uint16_t bits_per_sample; if (! TIFFGetField (tif, TIFFTAG_BITSPERSAMPLE, &bits_per_sample)) error ("Failed to obtain the bit depth"); if (bits_per_sample > 24) error ("Too high bit depth for a palette image"); uint32_t count = 1 << bits_per_sample; uint16_t *red, *green, *blue; validate_tiff_get_field (TIFFGetField (tif, TIFFTAG_COLORMAP, &red, &green, &blue)); tag_data_ovl(0) = octave_value (interpret_data (red, count, TIFFFieldDataType (fip))); tag_data_ovl(1) = octave_value (interpret_data (green, count, TIFFFieldDataType (fip))); tag_data_ovl(2) = octave_value (interpret_data (blue, count, TIFFFieldDataType (fip))); break; } case TIFFTAG_TRANSFERFUNCTION: { uint16_t samples_per_pixel; if (! TIFFGetField (tif, TIFFTAG_SAMPLESPERPIXEL, &samples_per_pixel)) error ("Failed to obtain the number of samples per pixel"); uint16_t bits_per_sample; if (! TIFFGetField (tif, TIFFTAG_BITSPERSAMPLE, &bits_per_sample)) error ("Failed to obtain the number of samples per pixel"); uint32_t count = 1 << bits_per_sample; uint16_t *ch1, *ch2, *ch3; if (samples_per_pixel == 1) { validate_tiff_get_field (TIFFGetField (tif, TIFFTAG_COLORMAP, &ch1)); tag_data_ovl(0) = octave_value (interpret_data (ch1, count, TIFFFieldDataType (fip))); } else { validate_tiff_get_field (TIFFGetField (tif, TIFFTAG_COLORMAP, &ch1, &ch2, &ch3)); tag_data_ovl(0) = octave_value (interpret_data (ch1, count, TIFFFieldDataType (fip))); tag_data_ovl(1) = octave_value (interpret_data (ch2, count, TIFFFieldDataType (fip))); tag_data_ovl(2) = octave_value (interpret_data (ch3, count, TIFFFieldDataType (fip))); } break; } case TIFFTAG_PAGENUMBER: case TIFFTAG_HALFTONEHINTS: case TIFFTAG_DOTRANGE: case TIFFTAG_YCBCRSUBSAMPLING: { uint16_t tag_part1, tag_part2; validate_tiff_get_field (TIFFGetField (tif, tag_id, &tag_part1, &tag_part2)); tag_data_ovl(0) = octave_value (interpret_data (&tag_part1, 1, TIFFFieldDataType (fip))); tag_data_ovl(1) = octave_value (interpret_data (&tag_part2, 1, TIFFFieldDataType (fip))); break; } case TIFFTAG_SUBIFD: { uint16_t count; uint64_t *offsets; validate_tiff_get_field (TIFFGetField (tif, tag_id, &count, &offsets)); tag_data_ovl = interpret_data (offsets, count, TIFFFieldDataType (fip)); break; } case TIFFTAG_EXTRASAMPLES: { uint16_t count; uint16_t *types; validate_tiff_get_field (TIFFGetField (tif, tag_id, &count, &types)); tag_data_ovl = interpret_data (types, count, TIFFFieldDataType (fip)); break; } // TODO(maged): These tags are more complex to implement // will be implemented and tested later. case TIFFTAG_XMLPACKET: case TIFFTAG_RICHTIFFIPTC: case TIFFTAG_PHOTOSHOP: case TIFFTAG_ICCPROFILE: { error ("Complex Tags not implemented"); break; } // Those two tags are not mentioned in the LibTIFF documentation // but are handled correctly by the library case TIFFTAG_ZIPQUALITY: case TIFFTAG_SGILOGDATAFMT: { tag_data_ovl = get_scalar_field_data (tif, fip); break; } default: tag_data_ovl = get_scalar_field_data (tif, fip); } return tag_data_ovl; } DEFUN_DLD (__open_tiff__, args, nargout, "Open a Tiff file and return its handle") { int nargin = args.length (); if (nargin == 0 || nargin > 2) { // TODO(maged): return invalid object instead?? error ("No filename supplied\n"); } std::string filename = args (0).string_value (); std::string mode = "r"; // TODO(maged): check valid mode if (nargin == 2) mode = args (1).string_value (); // TODO(maged): Look into unwind action TIFF *tif = TIFFOpen (filename.c_str (), mode.c_str ()); if (! tif) error ("Failed to open Tiff file\n"); // TODO(maged): use inheritance of octave_base_value instead octave_value tiff_ov = octave_value ((uint64_t)tif); return octave_value_list (tiff_ov); } DEFUN_DLD (__close_tiff__, args, nargout, "Close a tiff file") { int nargin = args.length (); if (nargin == 0) error ("No handle provided\n"); TIFF *tif = (TIFF *)(args (0).uint64_value ()); TIFFClose (tif); return octave_value_list (); } DEFUN_DLD (__tiff_get_tag__, args, nargout, "Get the value of a tag from a tiff image") { 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 ()); 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); return tag_data_ovl; } }