comparison libinterp/dldfcn/__tiff__.cc @ 31158:f2ae7763739a

Tiff: added writeEncodedTile method to read tiles from image * __tiff__.cc(F__tiff_read_encoded_tile__): added internal function to process readEncodedTile arguments. * __tiff__.cc(read_tile): implemented logic for reading tile from image file. * __tiff__.cc(handle_read_strip_or_tile): refactores common logic between read_strip and read_tile into a function. * Tiff.m: added readEncodedTile method to the Tiff class and added the necessary unit tests.
author magedrifaat <magedrifaat@gmail.com>
date Sat, 06 Aug 2022 21:59:26 +0200
parents dc3d2744916d
children e960e3a3b3f6
comparison
equal deleted inserted replaced
31157:dc3d2744916d 31158:f2ae7763739a
134 strip_dims = dim_vector (image_data->width, rows_in_strip, 1); 134 strip_dims = dim_vector (image_data->width, rows_in_strip, 1);
135 else 135 else
136 error ("Unsupported bit depth"); 136 error ("Unsupported bit depth");
137 137
138 T strip_data (strip_dims); 138 T strip_data (strip_dims);
139 139 uint8_t *strip_fvec
140 if (TIFFReadEncodedStrip (tif, strip_no, 140 = reinterpret_cast<uint8_t *> (strip_data.fortran_vec ());
141 strip_data.fortran_vec (), -1) == -1) 141
142 error ("Failed to read strip data"); 142 if (image_data->bits_per_sample == 8
143 || image_data->bits_per_sample == 16
144 || image_data->bits_per_sample == 32
145 || image_data->bits_per_sample == 64)
146 {
147 if (TIFFReadEncodedStrip (tif, strip_no, strip_fvec, -1) == -1)
148 error ("Failed to read strip data");
149 }
150 else if (image_data->bits_per_sample == 1)
151 {
152 if (image_data->samples_per_pixel != 1)
153 error ("Bi-Level images must have one channel only");
154
155 // Create a buffer to hold the packed strip data
156 // Unique pointers are faster than vectors for constant size buffers
157 std::unique_ptr<uint8_t []> strip_ptr
158 = std::make_unique<uint8_t []> (TIFFStripSize (tif));
159 uint8_t *strip_buf = strip_ptr.get ();
160 if (TIFFReadEncodedStrip (tif, strip_no, strip_buf, -1) == -1)
161 error ("Failed to read strip data");
162
163 // According to the format specification, the row should be byte
164 // aligned so the number of bytes is rounded up to the nearest byte
165 uint32_t padded_width = (image_data->width + 7) / 8;
166 // Packing the pixel data into bits
167 for (uint32_t row = 0; row < rows_in_strip; row++)
168 {
169 for (uint32_t col = 0; col < image_data->width; col++)
170 {
171 uint8_t shift = 7 - col % 8;
172 strip_fvec[col] = (strip_buf[col / 8] >> shift) & 0x1;
173 }
174 strip_fvec += image_data->width;
175 strip_buf += padded_width;
176 }
177 }
178 else
179 error ("Unsupported bit depth");
143 180
144 Array<octave_idx_type> perm (dim_vector (3, 1)); 181 Array<octave_idx_type> perm (dim_vector (3, 1));
145 if (image_data->planar_configuration == PLANARCONFIG_CONTIG) 182 if (image_data->planar_configuration == PLANARCONFIG_CONTIG)
146 { 183 {
147 perm(0) = 2; 184 perm(0) = 2;
155 perm(2) = 2; 192 perm(2) = 2;
156 } 193 }
157 194
158 strip_data = strip_data.permute (perm); 195 strip_data = strip_data.permute (perm);
159 return octave_value (strip_data); 196 return octave_value (strip_data);
197 }
198
199 template <typename T>
200 octave_value
201 read_tile (TIFF *tif, uint32_t tile_no, tiff_image_data *image_data)
202 {
203 // ASSUMES tiled image and tile_no is a valid zero-based tile
204 // index for the tif image
205
206 // TODO(maged): check matlab behavior
207 // TODO(maged): refactor into a function?
208 uint32_t tile_width, tile_height;
209 if (! TIFFGetField (tif, TIFFTAG_TILELENGTH, &tile_height))
210 error ("Filed to read tile length");
211
212 if (! TIFFGetField (tif, TIFFTAG_TILEWIDTH, &tile_width))
213 error ("Filed to read tile length");
214
215 if (tile_height == 0 || tile_height % 16 != 0
216 || tile_width == 0 || tile_width % 16 != 0)
217 error ("Tile dimesion tags are invalid");
218
219 dim_vector tile_dims;
220 if (image_data->planar_configuration == PLANARCONFIG_CONTIG)
221 {
222 tile_dims = dim_vector (image_data->samples_per_pixel, tile_width,
223 tile_height);
224 }
225 else if (image_data->planar_configuration == PLANARCONFIG_SEPARATE)
226 {
227 tile_dims = dim_vector (tile_width, tile_height, 1);
228 }
229 else
230 error ("Unsupported planar configuration");
231
232 T tile_data (tile_dims);
233 uint8_t *tile_fvec
234 = reinterpret_cast<uint8_t *> (tile_data.fortran_vec ());
235
236 if (image_data->bits_per_sample == 8
237 || image_data->bits_per_sample == 16
238 || image_data->bits_per_sample == 32
239 || image_data->bits_per_sample == 64)
240 {
241 if (TIFFReadEncodedTile (tif, tile_no, tile_fvec, -1) == -1)
242 error ("Failed to read tile data");
243 }
244 else if (image_data->bits_per_sample == 1)
245 {
246 if (image_data->samples_per_pixel != 1)
247 error ("Bi-Level images must have one channel only");
248
249 // Create a buffer to hold the packed tile data
250 // Unique pointers are faster than vectors for constant size buffers
251 std::unique_ptr<uint8_t []> tile_ptr
252 = std::make_unique<uint8_t []> (TIFFTileSize (tif));
253 uint8_t *tile_buf = tile_ptr.get ();
254 if (TIFFReadEncodedTile (tif, tile_no, tile_buf, -1) == -1)
255 error ("Failed to read tile data");
256
257 // unpack tile bits into output matrix cells
258 for (uint32_t row = 0; row < tile_height; row++)
259 {
260 for (uint32_t col = 0; col < tile_width; col++)
261 {
262 uint8_t shift = 7 - col % 8;
263 tile_fvec[col] = (tile_buf [col / 8] >> shift) & 0x1;
264 }
265 tile_fvec += tile_width;
266 tile_buf += tile_width / 8;
267 }
268 }
269 else
270 error ("Unsupported bit depth");
271
272 Array<octave_idx_type> perm (dim_vector (3, 1));
273 if (image_data->planar_configuration == PLANARCONFIG_CONTIG)
274 {
275 perm(0) = 2;
276 perm(1) = 1;
277 perm(2) = 0;
278 }
279 else if (image_data->planar_configuration == PLANARCONFIG_SEPARATE)
280 {
281 perm(0) = 1;
282 perm(1) = 0;
283 perm(2) = 2;
284 }
285
286 tile_data = tile_data.permute (perm);
287
288 // Get the actual tile dimensions
289 uint32_t tiles_across = (image_data->width + tile_width - 1)
290 / tile_width;
291 uint32_t tiles_down = (image_data->height + tile_height - 1)
292 / tile_height;
293 uint32_t corrected_width = tile_width;
294 uint32_t corrected_height = tile_height;
295 if (tile_no % tiles_across == tiles_across - 1)
296 corrected_width = image_data->width - tile_width * (tiles_across - 1);
297 if ((tile_no / tiles_across) % tiles_down == tiles_down - 1)
298 corrected_height = image_data->height - tile_height * (tiles_down - 1);
299
300 dim_vector corrected_dims;
301 if (image_data->planar_configuration == PLANARCONFIG_CONTIG)
302 corrected_dims = dim_vector (corrected_height, corrected_width,
303 image_data->samples_per_pixel);
304 else if (image_data->planar_configuration == PLANARCONFIG_SEPARATE)
305 corrected_dims = dim_vector (corrected_height, corrected_width);
306 // TODO(maged): confirm matlab behavior
307 tile_data.resize (corrected_dims);
308
309 return octave_value (tile_data);
310 }
311
312 template <typename T>
313 octave_value
314 read_strip_or_tile (TIFF *tif, uint32_t strip_tile_no,
315 tiff_image_data *image_data)
316 {
317 if (image_data->is_tiled)
318 return read_tile<T> (tif, strip_tile_no, image_data);
319 else
320 return read_strip<T> (tif, strip_tile_no, image_data);
321 }
322
323 octave_value
324 handle_read_strip_or_tile (TIFF *tif, uint32_t strip_tile_no)
325 {
326 // Obtain all necessary tags
327 tiff_image_data image_data (tif);
328
329 uint16_t sample_format;
330 if (! TIFFGetFieldDefaulted(tif, TIFFTAG_SAMPLEFORMAT, &sample_format))
331 error ("Failed to obtain a value for sample format");
332
333 if (sample_format == 3)
334 {
335 if (image_data.bits_per_sample != 32
336 && image_data.bits_per_sample != 64)
337 error ("Floating point images are only supported for bit depths of 32 and 64");
338 }
339 else if (sample_format != 1 && sample_format != 4)
340 error ("Unsupported sample format");
341
342 switch (image_data.bits_per_sample)
343 {
344 case 1:
345 return read_strip_or_tile<boolNDArray> (tif, strip_tile_no,
346 &image_data);
347 break;
348 case 8:
349 return read_strip_or_tile<uint8NDArray> (tif, strip_tile_no,
350 &image_data);
351 break;
352 case 16:
353 return read_strip_or_tile<uint16NDArray> (tif, strip_tile_no,
354 &image_data);
355 break;
356 case 32:
357 if (sample_format == 3)
358 return read_strip_or_tile<FloatNDArray> (tif, strip_tile_no,
359 &image_data);
360 else
361 return read_strip_or_tile<uint32NDArray> (tif, strip_tile_no,
362 &image_data);
363 break;
364 case 64:
365 if (sample_format == 3)
366 return read_strip_or_tile<NDArray> (tif, strip_tile_no,
367 &image_data);
368 else
369 return read_strip_or_tile<uint64NDArray> (tif, strip_tile_no,
370 &image_data);
371 break;
372 default:
373 error ("Unsupported bit depth");
374 }
160 } 375 }
161 376
162 template <typename T> 377 template <typename T>
163 octave_value 378 octave_value
164 read_stripped_image (TIFF *tif, tiff_image_data *image_data) 379 read_stripped_image (TIFF *tif, tiff_image_data *image_data)
1185 else 1400 else
1186 write_strip<T> (tif, strip_tile_no, strip_data, image_data); 1401 write_strip<T> (tif, strip_tile_no, strip_data, image_data);
1187 } 1402 }
1188 1403
1189 void 1404 void
1190 process_strip_or_tile (TIFF *tif, uint32_t strip_tile_no, 1405 handle_write_strip_or_tile (TIFF *tif, uint32_t strip_tile_no,
1191 octave_value data_ov, tiff_image_data *image_data) 1406 octave_value data_ov,
1407 tiff_image_data *image_data)
1192 { 1408 {
1193 1409
1194 // SampleFormat tag is not a required field and has a default value of 1 1410 // SampleFormat tag is not a required field and has a default value of 1
1195 // So we need to use TIFFGetFieldDefaulted in case it is not present in 1411 // So we need to use TIFFGetFieldDefaulted in case it is not present in
1196 // the file 1412 // the file
1735 err_disabled_feature ("read", "Tiff"); 1951 err_disabled_feature ("read", "Tiff");
1736 #endif 1952 #endif
1737 } 1953 }
1738 1954
1739 DEFUN_DLD (__tiff_read_encoded_strip__, args, nargout, 1955 DEFUN_DLD (__tiff_read_encoded_strip__, args, nargout,
1740 "Read the image in the current IFD") 1956 "Read a strip from the image in the current IFD")
1741 { 1957 {
1742 #if defined (HAVE_TIFF) 1958 #if defined (HAVE_TIFF)
1743 int nargin = args.length (); 1959 int nargin = args.length ();
1744 1960
1745 if (nargin != 2) 1961 if (nargin != 2)
1764 error ("Strip number out of bounds"); 1980 error ("Strip number out of bounds");
1765 1981
1766 // Convert from Octave's 1-based indexing to zero-based indexing 1982 // Convert from Octave's 1-based indexing to zero-based indexing
1767 strip_no--; 1983 strip_no--;
1768 1984
1769 // Obtain all necessary tags 1985 return octave_value_list (handle_read_strip_or_tile (tif, strip_no));
1770 tiff_image_data image_data (tif); 1986 #else
1771 1987 err_disabled_feature ("readEncodedStrip", "Tiff");
1772 uint16_t sample_format; 1988 #endif
1773 if (! TIFFGetFieldDefaulted(tif, TIFFTAG_SAMPLEFORMAT, &sample_format)) 1989 }
1774 error ("Failed to obtain a value for sample format"); 1990
1775 1991 DEFUN_DLD (__tiff_read_encoded_tile__, args, nargout,
1776 if (sample_format == 3) 1992 "Read a tile from the image in the current IFD")
1777 { 1993 {
1778 if (image_data.bits_per_sample != 32 && image_data.bits_per_sample != 64) 1994 #if defined (HAVE_TIFF)
1779 error ("Floating point images are only supported for bit depths of 32 and 64"); 1995 int nargin = args.length ();
1780 } 1996
1781 else if (sample_format != 1 && sample_format != 4) 1997 if (nargin != 2)
1782 error ("Unsupported sample format"); 1998 error ("rong number of arguments");
1783 1999
1784 octave_value_list retval; 2000 TIFF *tif = (TIFF *)(args(0).uint64_value ());
1785 switch (image_data.bits_per_sample) 2001
1786 { 2002 // TODO(maged): nargout and ycbcr
1787 case 1: 2003 octave_unused_parameter (nargout);
1788 retval(0) = read_strip<boolNDArray> (tif, strip_no, &image_data); 2004
1789 break; 2005 if (! TIFFIsTiled (tif))
1790 case 8: 2006 error ("The image is stripped not tiled");
1791 retval(0) = read_strip<uint8NDArray> (tif, strip_no, &image_data); 2007
1792 break; 2008 // TODO(maged): what is the behavior in matlab
1793 case 16: 2009 uint32_t tile_no;
1794 retval(0) = read_strip<uint16NDArray> (tif, strip_no, &image_data); 2010 if (args(1).is_scalar_type ())
1795 break; 2011 tile_no = args(1).uint32_scalar_value ();
1796 case 32: 2012 else
1797 if (sample_format == 3) 2013 error ("Expected scalar for tile number");
1798 retval(0) = read_strip<FloatNDArray> (tif, strip_no, &image_data); 2014
1799 else 2015 if (tile_no < 1 || tile_no > TIFFNumberOfTiles (tif))
1800 retval(0) = read_strip<uint32NDArray> (tif, strip_no, &image_data); 2016 error ("Tile number out of bounds");
1801 break; 2017
1802 case 64: 2018 // Convert from Octave's 1-based indexing to zero-based indexing
1803 if (sample_format == 3) 2019 tile_no--;
1804 retval(0) = read_strip<NDArray> (tif, strip_no, &image_data); 2020
1805 else 2021 return octave_value_list (handle_read_strip_or_tile (tif, tile_no));
1806 retval(0) = read_strip<uint64NDArray> (tif, strip_no, &image_data);
1807 break;
1808 default:
1809 error ("Unsupported bit depth");
1810 }
1811
1812 return retval;
1813 #else 2022 #else
1814 err_disabled_feature ("readEncodedStrip", "Tiff"); 2023 err_disabled_feature ("readEncodedStrip", "Tiff");
1815 #endif 2024 #endif
1816 } 2025 }
1817 2026
1932 2141
1933 uint32_t strip_no = args(1).uint32_scalar_value (); 2142 uint32_t strip_no = args(1).uint32_scalar_value ();
1934 if (strip_no < 1 || strip_no > TIFFNumberOfStrips (tif)) 2143 if (strip_no < 1 || strip_no > TIFFNumberOfStrips (tif))
1935 error ("Strip number out of range"); 2144 error ("Strip number out of range");
1936 2145
1937 process_strip_or_tile (tif, strip_no, args(2), &image_data); 2146 handle_write_strip_or_tile (tif, strip_no, args(2), &image_data);
1938 2147
1939 return octave_value_list (); 2148 return octave_value_list ();
1940 #else 2149 #else
1941 err_disabled_feature ("writeEncodedStrip", "Tiff"); 2150 err_disabled_feature ("writeEncodedStrip", "Tiff");
1942 #endif 2151 #endif
1966 2175
1967 uint32_t tile_no = args(1).uint32_scalar_value (); 2176 uint32_t tile_no = args(1).uint32_scalar_value ();
1968 if (tile_no < 1 || tile_no > TIFFNumberOfTiles (tif)) 2177 if (tile_no < 1 || tile_no > TIFFNumberOfTiles (tif))
1969 error ("Tile number out of range"); 2178 error ("Tile number out of range");
1970 2179
1971 process_strip_or_tile (tif, tile_no, args(2), &image_data); 2180 handle_write_strip_or_tile (tif, tile_no, args(2), &image_data);
1972 2181
1973 return octave_value_list (); 2182 return octave_value_list ();
1974 #else 2183 #else
1975 err_disabled_feature ("writeEncodedTile", "Tiff"); 2184 err_disabled_feature ("writeEncodedTile", "Tiff");
1976 #endif 2185 #endif