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