1 // This is core/vil/file_formats/vil_tiff.cxx
2 #include <cstring>
3 #include <iostream>
4 #include <algorithm>
5 #include <sstream>
6 #include "vil_tiff.h"
7 //:
8 // \file
9 // See vil_tiff.h for a description of this file.
10 //
11 // \author awf@robots.ox.ac.uk
12 //
13 // \verbatim
14 // Modifications:
15 // 2001-11-09 K.Y.McGaul Use dflt value for orientation when it can't be read
16 // 2005-12-xx J.L. Mundy Essentially a complete rewrite to support blocking.
17 // Cleaner struct: hdr params moved to vil_tiff_header
18 // \endverbatim
19
20 #include <cassert>
21 #ifdef _MSC_VER
22 # include "vcl_msvc_warnings.h"
23 #endif
24 #include "vil/vil_stream.h"
25 #include "vil/vil_property.h"
26 #include "vil/vil_image_view.h"
27 #include "vil/vil_memory_chunk.h"
28 #include "vil/vil_copy.h"
29 #include "vil/vil_image_list.h"
30 #include "vil_tiff_header.h"
31 #include "vil/vil_exception.h"
32 //#define DEBUG
33
34 // Constants
35 char const * vil_tiff_format_tag = "tiff";
36
37 static unsigned
nimg(TIFF * tif)38 nimg(TIFF * tif)
39 {
40 if (!tif)
41 return 0;
42 TIFFSetDirectory(tif, 0);
43 unsigned int dircount = 0;
44 do
45 {
46 dircount++;
47 } while (TIFFReadDirectory(tif));
48 return dircount;
49 }
50
51
52 bool
vil_tiff_file_format_probe(vil_stream * is)53 vil_tiff_file_format_probe(vil_stream * is)
54 {
55 // The byte ordering in a TIFF image (usually) depends on the byte-order
56 // of the writing host. The header is always 4 bytes.
57
58 char hdr[4];
59 auto read = (unsigned)is->read(hdr, sizeof hdr);
60 if (read < sizeof hdr)
61 return false;
62
63 // First two bytes specify the file byte-order (0x4D4D=big, 0x4949=little).
64 // Second two bytes specify the TIFF version (we expect 0x2A for tiff and 0x2B for bigtiff).
65 // For information about BigTIFF refers to http://www.remotesensing.org/libtiff/bigtiffdesign.html
66 // So,
67 // 0x4D 0x4D 0x00 0x2A
68
69 // and
70 // 0x49 0x49 0x2A 0x00
71 // or
72 // 0x49 0x49 0x2B 0x00
73 // are invalid TIFF headers.
74 if (hdr[0] == 0x4D && hdr[1] == 0x4D && hdr[2] == 0x00 && (hdr[3] == 0x2A || hdr[3] == 0x2B))
75 return true;
76
77 else if (hdr[0] == 0x49 && hdr[1] == 0x49 && (hdr[2] == 0x2A || hdr[2] == 0x2B) && hdr[3] == 0x00)
78 return true;
79
80 else if (((hdr[0] == 0x4D && hdr[1] == 0x4D) || (hdr[0] == 0x49 && hdr[1] == 0x49)) &&
81 ((hdr[2] == 0x00 && hdr[3] == 0x2A) || (hdr[2] == 0x2A && hdr[3] == 0x00)))
82 {
83 std::cerr << __FILE__ ": suspicious TIFF header\n";
84 return true; // allow it.
85 }
86
87 else
88 return false;
89 }
90
91 struct tif_stream_structures
92 {
tif_stream_structurestif_stream_structures93 tif_stream_structures(vil_stream * vs_)
94 : vs(vs_)
95 , filesize(0) /*, sample_format( SAMPLEFORMAT_VOID ), buf(0) */
96 {
97 if (vs)
98 vs->ref();
99 }
100
~tif_stream_structurestif_stream_structures101 ~tif_stream_structures()
102 { /* delete[] buf; */
103 if (vs)
104 vs->unref();
105 }
106
107 TIFF * tif;
108 vil_stream * vs;
109 vil_streampos filesize;
110 };
111
112 static tsize_t
vil_tiff_readproc(thandle_t h,tdata_t buf,tsize_t n)113 vil_tiff_readproc(thandle_t h, tdata_t buf, tsize_t n)
114 {
115 auto * p = (tif_stream_structures *)h;
116 long long no = static_cast<long long>(n);
117 if (no > p->filesize)
118 p->filesize = n;
119 // there should be no problem with this case because n
120 // is also of type tsize_t
121 auto ret = (tsize_t)p->vs->read(buf, n);
122 return ret;
123 }
124
125 static tsize_t
vil_tiff_writeproc(thandle_t h,tdata_t buf,tsize_t n)126 vil_tiff_writeproc(thandle_t h, tdata_t buf, tsize_t n)
127 {
128 auto * p = (tif_stream_structures *)h;
129 // there should be no problem with this case because n
130 // is also of type tsize_t
131 auto ret = (tsize_t)p->vs->write(buf, n);
132 vil_streampos s = p->vs->tell();
133 if (s > p->filesize)
134 p->filesize = s;
135 return ret;
136 }
137
138 static toff_t
vil_tiff_seekproc(thandle_t h,toff_t offset,int whence)139 vil_tiff_seekproc(thandle_t h, toff_t offset, int whence)
140 {
141 auto * p = (tif_stream_structures *)h;
142 if (whence == SEEK_SET)
143 p->vs->seek(offset);
144 else if (whence == SEEK_CUR)
145 p->vs->seek(p->vs->tell() + offset);
146 else if (whence == SEEK_END)
147 p->vs->seek(p->filesize + offset);
148 vil_streampos s = p->vs->tell();
149 if (s > p->filesize)
150 p->filesize = s;
151 return (toff_t)s;
152 }
153
154 static int
vil_tiff_closeproc(thandle_t h)155 vil_tiff_closeproc(thandle_t h)
156 {
157 auto * p = (tif_stream_structures *)h;
158 p->vs->unref();
159 p->vs = nullptr;
160 delete p;
161 return 0;
162 }
163
vil_tiff_sizeproc(thandle_t)164 static toff_t vil_tiff_sizeproc(thandle_t)
165 {
166 // TODO
167 #ifdef DEBUG
168 std::cerr << "Warning: vil_tiff_sizeproc() not yet implemented\n";
169 #endif
170 return (toff_t)(-1); // could be unsigned - avoid compiler warning
171 }
172
173 static int
vil_tiff_mapfileproc(thandle_t,tdata_t *,toff_t *)174 vil_tiff_mapfileproc(thandle_t, tdata_t *, toff_t *)
175 {
176 // TODO: Add mmap support to vil_tiff_mapfileproc
177 #ifdef DEBUG
178 std::cerr << "Warning: mmap support not yet in vil_tiff_mapfileproc()\n";
179 #endif
180 return 0;
181 }
182
vil_tiff_unmapfileproc(thandle_t,tdata_t,toff_t)183 static void vil_tiff_unmapfileproc(thandle_t, tdata_t, toff_t) {}
184
185
186 static TIFF *
open_tiff(tif_stream_structures * tss,const char * mode)187 open_tiff(tif_stream_structures * tss, const char * mode)
188 {
189 tss->vs->seek(0L);
190 #if HAS_GEOTIFF
191 TIFF * tiff = XTIFFClientOpen("unknown filename",
192 mode, // read, enable strip chopping
193 (thandle_t)tss,
194 vil_tiff_readproc,
195 vil_tiff_writeproc,
196 vil_tiff_seekproc,
197 vil_tiff_closeproc,
198 vil_tiff_sizeproc,
199 vil_tiff_mapfileproc,
200 vil_tiff_unmapfileproc);
201 #else // this file is only included if HAS TIFF is defined vil_file_format.cxx
202 TIFF * tiff = TIFFClientOpen("unknown filename",
203 mode, // read, enable strip chopping
204 (thandle_t)tss,
205 vil_tiff_readproc,
206 vil_tiff_writeproc,
207 vil_tiff_seekproc,
208 vil_tiff_closeproc,
209 vil_tiff_sizeproc,
210 vil_tiff_mapfileproc,
211 vil_tiff_unmapfileproc);
212 #endif // HAS_GEOTIFF
213
214 if (!tiff)
215 return nullptr;
216 else
217 return tiff;
218 }
219
220 vil_image_resource_sptr
make_input_image(vil_stream * is)221 vil_tiff_file_format::make_input_image(vil_stream * is)
222 {
223 if (!vil_tiff_file_format_probe(is))
224 return nullptr;
225 auto * tss = new tif_stream_structures(is);
226
227 tss->tif = open_tiff(tss, "rC");
228
229 if (!tss->tif)
230 return nullptr;
231 auto * h = new vil_tiff_header(tss->tif);
232
233 if (!h->format_supported)
234 {
235 #if HAS_GEOTIFF
236 XTIFFClose(tss->tif);
237 #else
238 TIFFClose(tss->tif);
239 #endif // HAS_GEOTIFF
240 delete h;
241 return nullptr;
242 }
243 unsigned n = nimg(tss->tif);
244 tif_smart_ptr tif_sptr = new tif_ref_cnt(tss->tif);
245 return new vil_tiff_image(tif_sptr, h, n);
246 }
247
248 vil_pyramid_image_resource_sptr
make_input_pyramid_image(char const * file)249 vil_tiff_file_format::make_input_pyramid_image(char const * file)
250 {
251 bool trace = false;
252 if (vil_image_list::vil_is_directory(file))
253 return nullptr;
254 TIFF * in = TIFFOpen(file, "rC");
255 if (!in)
256 return nullptr;
257 bool open_for_reading = true;
258 if (trace) // find test failure
259 std::cerr << "make_input_pyramid_image::opening multi-image tiff pyramid resource\n";
260 tif_smart_ptr tif_sptr = new tif_ref_cnt(in);
261 vil_pyramid_image_resource_sptr pyr = new vil_tiff_pyramid_resource(tif_sptr, open_for_reading);
262 if (pyr->nlevels() <= 1)
263 return nullptr;
264 else
265 return pyr;
266 }
267
268 static std::string
level_filename(std::string & directory,std::string & filename,unsigned level)269 level_filename(std::string & directory, std::string & filename, unsigned level)
270 {
271 std::string slash;
272
273 #ifdef _WIN32
274 slash = "\\";
275 #else
276 slash = "/";
277 #endif
278 std::stringstream cs;
279 cs << level;
280 return directory + slash + filename + cs.str();
281 }
282
283 vil_pyramid_image_resource_sptr
make_pyramid_image_from_base(char const * file,vil_image_resource_sptr const & base_image,unsigned nlevels,char const * temp_dir)284 vil_tiff_file_format::make_pyramid_image_from_base(char const * file,
285 vil_image_resource_sptr const & base_image,
286 unsigned nlevels,
287 char const * temp_dir)
288 {
289 { // scope for writing the resources
290 vil_pyramid_image_resource_sptr pyr = make_pyramid_output_image(file);
291 pyr->put_resource(base_image);
292 // Create the other pyramid levels
293 { // scope for resource files
294 std::string d = temp_dir;
295 std::string fn = "tempR";
296 vil_image_resource_sptr image = base_image;
297 for (unsigned L = 1; L < nlevels; ++L)
298 {
299 std::cout << "Decimating Level " << L << std::endl;
300 std::string full_filename = level_filename(d, fn, L) + ".tif";
301 image = vil_pyramid_image_resource::decimate(image, full_filename.c_str());
302 }
303 } // end program scope to close resource files
304
305 // reopen them for reading
306 { // scope for il resources
307 vil_image_list il(temp_dir);
308 std::vector<vil_image_resource_sptr> rescs = il.resources();
309 for (auto & resc : rescs)
310 pyr->put_resource(resc);
311 } // close il resources
312 } // close pyr
313
314 // clean up the temporary directory
315 vil_image_list vl(temp_dir);
316 if (!vl.clean_directory())
317 {
318 std::cout << "Warning: In vil_tiff::make_pyramid_from_base(..) -"
319 << " temporary directory not cleaned\n";
320 }
321 // reopen for reading
322 return make_input_pyramid_image(file);
323 }
324
325 vil_blocked_image_resource_sptr
make_blocked_output_image(vil_stream * vs,unsigned nx,unsigned ny,unsigned nplanes,unsigned size_block_i,unsigned size_block_j,enum vil_pixel_format format)326 vil_tiff_file_format::make_blocked_output_image(vil_stream * vs,
327 unsigned nx,
328 unsigned ny,
329 unsigned nplanes,
330 unsigned size_block_i,
331 unsigned size_block_j,
332 enum vil_pixel_format format)
333 {
334 if (size_block_i % 16 != 0 || size_block_j % 16 != 0)
335 {
336 std::cerr << "In vil_tiff_file_format - Block dimensions must be a multiple of 16\n";
337 return nullptr;
338 }
339
340 auto * tss = new tif_stream_structures(vs);
341 tss->filesize = 0;
342 std::string mode("w");
343 vxl_uint_64 size_needed = vxl_uint_64(nx) * vxl_uint_64(ny) * vxl_uint_64(nplanes) *
344 vil_pixel_format_sizeof_components(format) * vil_pixel_format_num_components(format);
345 bool const bigtiff_needed = size_needed >= vxl_uint_64(0x7FFFFFFF);
346 if (bigtiff_needed)
347 mode += '8'; // enable bigtiff
348 tss->tif = open_tiff(tss, mode.c_str());
349 if (!tss->tif)
350 return nullptr;
351
352 // size_block_i==0 && size_block_j==0 specifies strips of one scanline
353 // this constructor for h defines that the resource is to
354 // be setup for writing
355 auto * h = new vil_tiff_header(tss->tif, nx, ny, nplanes, format, size_block_i, size_block_j);
356 if (!h->format_supported)
357 {
358 #if HAS_GEOTIFF
359 XTIFFClose(tss->tif);
360 #else
361 TIFFClose(tss->tif);
362 #endif // HAS_GEOTIFF
363 delete h;
364 return nullptr;
365 }
366 tif_smart_ptr tsptr = new tif_ref_cnt(tss->tif);
367 return new vil_tiff_image(tsptr, h);
368 }
369
370
371 vil_image_resource_sptr
make_output_image(vil_stream * vs,unsigned ni,unsigned nj,unsigned nplanes,enum vil_pixel_format format)372 vil_tiff_file_format::make_output_image(vil_stream * vs,
373 unsigned ni,
374 unsigned nj,
375 unsigned nplanes,
376 enum vil_pixel_format format)
377 {
378 return make_blocked_output_image(vs, ni, nj, nplanes, 0, 0, format).ptr();
379 }
380
381 vil_pyramid_image_resource_sptr
make_pyramid_output_image(char const * filename)382 vil_tiff_file_format::make_pyramid_output_image(char const * filename)
383 {
384 TIFF * out = TIFFOpen(filename, "w");
385 if (!out)
386 return nullptr;
387 bool open_for_reading = false;
388 tif_smart_ptr tsptr = new tif_ref_cnt(out);
389 return new vil_tiff_pyramid_resource(tsptr, open_for_reading);
390 }
391
392 char const *
tag() const393 vil_tiff_file_format::tag() const
394 {
395 return vil_tiff_format_tag;
396 }
397
398 /////////////////////////////////////////////////////////////////////////////
399
400
401 /////////////////////////////////////////////////////////////////////////////
402
403
vil_tiff_image(tif_smart_ptr const & tif_sptr,vil_tiff_header * th,const unsigned nimages)404 vil_tiff_image::vil_tiff_image(tif_smart_ptr const & tif_sptr, vil_tiff_header * th, const unsigned nimages)
405 : t_(tif_sptr)
406 , h_(th)
407 , index_(0)
408 , nimages_(nimages)
409 {}
410
411 bool
get_property(char const * tag,void * value) const412 vil_tiff_image::get_property(char const * tag, void * value) const
413 {
414 if (std::strcmp(vil_property_quantisation_depth, tag) == 0)
415 {
416 if (value)
417 *static_cast<unsigned *>(value) = h_->bits_per_sample.val;
418 return true;
419 }
420 if (std::strcmp(vil_property_size_block_i, tag) == 0)
421 {
422 if (!h_->is_tiled())
423 return false;
424 if (value)
425 *static_cast<unsigned *>(value) = this->size_block_i();
426 return true;
427 }
428
429 if (std::strcmp(vil_property_size_block_j, tag) == 0)
430 {
431 if (!h_->is_tiled())
432 return false;
433 if (value)
434 *static_cast<unsigned *>(value) = this->size_block_j();
435 return true;
436 }
437
438 return false;
439 }
440
441 bool
set_compression_method(compression_methods cm)442 vil_tiff_image::set_compression_method(compression_methods cm)
443 {
444 TIFF * const tif = t_.tif();
445 if (tif)
446 {
447 int status = TIFFSetField(tif, TIFFTAG_COMPRESSION, int(cm));
448 return bool(status);
449 }
450 else
451 return false;
452 }
453
454 bool
set_compression_quality(int quality)455 vil_tiff_image::set_compression_quality(int quality)
456 {
457 TIFF * const tif = t_.tif();
458 if (tif)
459 {
460 int status = TIFFSetField(tif, TIFFTAG_JPEGQUALITY, quality);
461 return bool(status);
462 }
463 else
464 return false;
465 }
466
467 #if HAS_GEOTIFF
468 vil_geotiff_header *
get_geotiff_header()469 vil_tiff_image::get_geotiff_header()
470 {
471 auto * gtif = new vil_geotiff_header(t_.tif());
472 if (gtif->gtif_number_of_keys() == 0)
473 {
474 delete gtif;
475 return nullptr;
476 }
477
478 return gtif;
479 }
480 #endif
481
482 vil_pixel_format
pixel_format() const483 vil_tiff_image::pixel_format() const
484 {
485 return h_->pix_fmt;
486 }
487
~vil_tiff_image()488 vil_tiff_image::~vil_tiff_image()
489 {
490 delete h_;
491 }
492
493 //////
494 // Lifted from nitf2. Maybe generalize to support other file formats
495 //////
496 char const *
file_format() const497 vil_tiff_image::file_format() const
498 {
499 return vil_tiff_format_tag;
500 }
501
502 static void
tif_swap16(vxl_byte * a,unsigned n)503 tif_swap16(vxl_byte * a, unsigned n)
504 {
505 for (unsigned i = 0; i < n * 2; i += 2)
506 std::swap(a[i + 0], a[i + 1]);
507 }
508
509 static void
tif_swap32(vxl_byte * a,unsigned n)510 tif_swap32(vxl_byte * a, unsigned n)
511 {
512 for (unsigned i = 0; i < n * 4; i += 4)
513 {
514 std::swap(a[i + 0], a[i + 3]);
515 std::swap(a[i + 1], a[i + 2]);
516 }
517 }
518
519 static void
endian_swap(vxl_byte * a,unsigned n_bytes,unsigned bytes_per_sample)520 endian_swap(vxl_byte * a, unsigned n_bytes, unsigned bytes_per_sample)
521 {
522 switch (bytes_per_sample)
523 {
524 case 1:
525 break; // do nothing
526 case 2:
527 tif_swap16(a, n_bytes / 2);
528 break; // 16 bit
529 case 4:
530 tif_swap32(a, n_bytes / 4);
531 break; // 32 bit
532 default:
533 assert(!"Unsupported number of bytes per sample.");
534 }
535 }
536
537 template <>
538 bool *
tiff_byte_align_data(bool * in_data,unsigned num_samples,unsigned in_bits_per_sample,bool * out_data)539 tiff_byte_align_data<bool>(bool * in_data, unsigned num_samples, unsigned in_bits_per_sample, bool * out_data)
540 {
541 switch (sizeof(bool))
542 {
543 case 1:
544 tiff_byte_align_data((vxl_byte *)in_data, num_samples, in_bits_per_sample, (vxl_byte *)out_data);
545 break;
546 case 2:
547 tiff_byte_align_data((vxl_uint_16 *)in_data, num_samples, in_bits_per_sample, (vxl_uint_16 *)out_data);
548 break;
549 case 4:
550 tiff_byte_align_data((vxl_uint_32 *)in_data, num_samples, in_bits_per_sample, (vxl_uint_32 *)out_data);
551 break;
552 default:
553 assert(!"Unsupported size of bool in tiff file format.");
554 }
555 return out_data;
556 }
557
558 // the sample is an integral data type
559 bool
integral_type(unsigned bits_per_sample)560 integral_type(unsigned bits_per_sample)
561 {
562 switch (bits_per_sample)
563 {
564 case 8:
565 case 16:
566 case 32:
567 return true;
568 default:
569 break;
570 }
571 return false;
572 }
573
574 template <class T>
575 vil_memory_chunk_sptr
tiff_maybe_byte_align_data(vil_memory_chunk_sptr in_data,unsigned num_samples,unsigned in_bits_per_sample,unsigned bytes_per_block)576 tiff_maybe_byte_align_data(vil_memory_chunk_sptr in_data,
577 unsigned num_samples,
578 unsigned in_bits_per_sample,
579 unsigned bytes_per_block)
580 {
581 if (!integral_type(in_bits_per_sample))
582 {
583 vil_memory_chunk_sptr new_memory = new vil_memory_chunk(bytes_per_block, in_data->pixel_format());
584 #ifdef DEBUG
585 std::cout << "Debug tiff_byte_align_data:"
586 << " Num Samples = " << num_samples << " Input Bits/Sample = " << in_bits_per_sample
587 << " Bytes/Block = " << bytes_per_block
588 << " Output Bytes/Sample = " << vil_pixel_format_sizeof_components(in_data->pixel_format())
589 << std::flush;
590 #endif
591 T * out_ptr = reinterpret_cast<T *>(new_memory->data());
592 T * in_ptr = reinterpret_cast<T *>(in_data->data());
593 tiff_byte_align_data(in_ptr, num_samples, in_bits_per_sample, out_ptr);
594 #ifdef DEBUG
595 std::cout << " .\n" << std::flush;
596 #endif
597 return new_memory;
598 }
599 return in_data;
600 }
601
602 // don't do anything for float and double (bit shifting isn't allowed)
603 template <>
604 vil_memory_chunk_sptr
tiff_maybe_byte_align_data(vil_memory_chunk_sptr in_data,unsigned,unsigned,unsigned)605 tiff_maybe_byte_align_data<float>(vil_memory_chunk_sptr in_data,
606 unsigned /* num_samples */,
607 unsigned /* in_bits_per_sample */,
608 unsigned /* bytes per block */)
609 {
610 return in_data;
611 }
612
613 template <>
614 vil_memory_chunk_sptr
tiff_maybe_byte_align_data(vil_memory_chunk_sptr in_data,unsigned,unsigned,unsigned)615 tiff_maybe_byte_align_data<double>(vil_memory_chunk_sptr in_data,
616 unsigned /* num_samples */,
617 unsigned /* in_bits_per_sample */,
618 unsigned /* bytes per block */)
619 {
620 return in_data;
621 }
622
623 ////////// End of lifted material //////
624
625 // simple virtual methods on vil_image_resource
626 unsigned
nplanes() const627 vil_tiff_image::nplanes() const
628 {
629 return h_->nplanes;
630 }
631
632 unsigned
ni() const633 vil_tiff_image::ni() const
634 {
635 if (h_->image_width.valid)
636 return h_->image_width.val;
637 return 0;
638 }
639
640 unsigned
nj() const641 vil_tiff_image::nj() const
642 {
643 if (h_->image_length.valid)
644 return h_->image_length.val;
645 return 0;
646 }
647
648 //: block size in cols
649 unsigned
size_block_i() const650 vil_tiff_image::size_block_i() const
651 {
652 if (h_->tile_width.valid)
653 return static_cast<unsigned>(h_->tile_width.val);
654 if (h_->image_width.valid)
655 return static_cast<unsigned>(h_->image_width.val);
656 return 0;
657 }
658
659 //: block size in rows.
660 // For strips, the number of rows per strip can be larger
661 // than the image length but data is only valid for the number of actual
662 // image rows. For images with multiple strips, the last strip may be
663 // cropped by the actual number of image rows.
664 unsigned
size_block_j() const665 vil_tiff_image::size_block_j() const
666 {
667 if (h_->tile_length.valid)
668 return static_cast<unsigned>(h_->tile_length.val);
669
670 auto bps = static_cast<unsigned>(h_->bytes_per_strip());
671 auto bpl = static_cast<unsigned>(h_->bytes_per_line());
672 unsigned size = bps / bpl;
673 return size;
674 return 0;
675 }
676
677 //: Number of blocks in image width
678 unsigned
n_block_i() const679 vil_tiff_image::n_block_i() const
680 {
681 if (h_->tile_width.valid)
682 return static_cast<unsigned>(h_->tiles_across());
683 return 1;
684 }
685
686 //: Number of blocks in image height
687 unsigned
n_block_j() const688 vil_tiff_image::n_block_j() const
689 {
690 if (h_->tile_length.valid && h_->image_length.valid)
691 return static_cast<unsigned>(h_->tiles_down());
692 return static_cast<unsigned>(h_->strips_per_image());
693 }
694
695 ///// end of simple virtual methods
696
697 unsigned
block_index(unsigned block_i,unsigned block_j) const698 vil_tiff_image::block_index(unsigned block_i, unsigned block_j) const
699 {
700 return block_j * n_block_i() + block_i;
701 }
702
703 // the number of samples per block, irrespective of bit resolution
704 unsigned
samples_per_block() const705 vil_tiff_image::samples_per_block() const
706 {
707 if (h_->samples_per_pixel.valid)
708 return static_cast<unsigned>(h_->samples_per_pixel.val * size_block_i() * size_block_j());
709 return 0;
710 }
711
712 //: Transfer data from block to memory chunk, row by row
713 // Since view and block are the same we can just blast across
714 void
copy_byte_block(vxl_byte * data,const vxl_uint_32 nbytes,vil_memory_chunk_sptr & cnk) const715 vil_tiff_image::copy_byte_block(vxl_byte * data, const vxl_uint_32 nbytes, vil_memory_chunk_sptr & cnk) const
716 {
717 if (nbytes == 0)
718 return;
719 auto * c_data = reinterpret_cast<vxl_byte *>(cnk->data());
720 std::memcpy(c_data, data, nbytes);
721 }
722
723 //: map the input buffer into the view.
724 // Note strips won't trigger byte
725 // alignment, because they are already aligned at this point.
726 vil_image_view_base_sptr
view_from_buffer(vil_pixel_format & fmt,vil_memory_chunk_sptr const & buf,unsigned samples_per_block,unsigned bits_per_sample) const727 vil_tiff_image::view_from_buffer(vil_pixel_format & fmt,
728 vil_memory_chunk_sptr const & buf,
729 unsigned samples_per_block,
730 unsigned bits_per_sample) const
731 {
732 vil_image_view_base_sptr view = nullptr;
733 vil_memory_chunk_sptr buf_out;
734 unsigned spp = h_->samples_per_pixel.val;
735 switch (fmt)
736 {
737 #define GET_BLOCK_CASE(FORMAT, T) \
738 case FORMAT: { \
739 vil_image_view_base_sptr view; \
740 buf_out = tiff_maybe_byte_align_data<T>( \
741 buf, samples_per_block, bits_per_sample, samples_per_block * vil_pixel_format_sizeof_components(fmt)); \
742 view = new vil_image_view<T>(buf_out, \
743 reinterpret_cast<T *>(buf_out->data()), \
744 size_block_i(), \
745 size_block_j(), \
746 spp, \
747 spp, \
748 size_block_i() * spp, \
749 1); \
750 return view; \
751 }
752 GET_BLOCK_CASE(VIL_PIXEL_FORMAT_BYTE, vxl_byte);
753 GET_BLOCK_CASE(VIL_PIXEL_FORMAT_SBYTE, vxl_sbyte);
754 #if VXL_HAS_INT_64
755 GET_BLOCK_CASE(VIL_PIXEL_FORMAT_UINT_64, vxl_uint_64);
756 GET_BLOCK_CASE(VIL_PIXEL_FORMAT_INT_64, vxl_int_64);
757 #endif
758 GET_BLOCK_CASE(VIL_PIXEL_FORMAT_UINT_32, vxl_uint_32);
759 GET_BLOCK_CASE(VIL_PIXEL_FORMAT_INT_32, vxl_int_32);
760 GET_BLOCK_CASE(VIL_PIXEL_FORMAT_UINT_16, vxl_uint_16);
761 GET_BLOCK_CASE(VIL_PIXEL_FORMAT_INT_16, vxl_int_16);
762 GET_BLOCK_CASE(VIL_PIXEL_FORMAT_BOOL, bool);
763 GET_BLOCK_CASE(VIL_PIXEL_FORMAT_FLOAT, float);
764 GET_BLOCK_CASE(VIL_PIXEL_FORMAT_DOUBLE, double);
765 #undef GET_BLOCK_CASE
766 default:
767 assert(!"Unknown vil data type in tiff file format");
768 break;
769 }
770 return view;
771 }
772
773 // this internal block accessor is used for both tiled and
774 // striped encodings
775 vil_image_view_base_sptr
get_block(unsigned block_index_i,unsigned block_index_j) const776 vil_tiff_image::get_block(unsigned block_index_i, unsigned block_index_j) const
777 {
778 // the only two possibilities
779 assert(h_->is_tiled() || h_->is_striped());
780 //
781 // If there are multiple images in the file it is
782 // necessary to set the TIFF directory and file header corresponding to
783 // this resource according to the index
784 //
785 if (nimages_ > 1)
786 {
787 if (TIFFSetDirectory(t_.tif(), index_) <= 0)
788 return nullptr;
789 auto * h = new vil_tiff_header(t_.tif());
790 // Cast away const
791 auto * ti = (vil_tiff_image *)this;
792 delete h_;
793 ti->h_ = h;
794 }
795
796 vil_image_view_base_sptr view = nullptr;
797
798 // allocate input memory
799 // input memory
800 unsigned encoded_block_size = h_->encoded_bytes_per_block();
801 assert(encoded_block_size > 0);
802 // vxl_byte* data = new vxl_byte[encoded_block_size];
803
804 // compute the block index
805 unsigned blk_indx = this->block_index(block_index_i, block_index_j);
806
807
808 vil_pixel_format fmt = vil_pixel_format_component_format(h_->pix_fmt);
809
810 // input memory chunk
811 vil_memory_chunk_sptr buf = new vil_memory_chunk(encoded_block_size, fmt);
812 unsigned expanded_sample_bytes = vil_pixel_format_sizeof_components(fmt);
813
814
815 if (h_->is_tiled())
816 {
817 auto * data = new vxl_byte[encoded_block_size];
818 if (TIFFReadEncodedTile(t_.tif(), blk_indx, data, (tsize_t)-1) <= 0)
819 {
820 delete[] data;
821 return view;
822 }
823 this->copy_byte_block(data, encoded_block_size, buf);
824 delete[] data;
825 if (h_->need_byte_swap())
826 endian_swap(reinterpret_cast<vxl_byte *>(buf->data()), encoded_block_size, expanded_sample_bytes);
827 return this->fill_block_from_tile(buf);
828 }
829
830 if (h_->is_striped() && h_->planar_config.val == 1)
831 {
832 auto * data = new vxl_byte[encoded_block_size];
833 if (TIFFReadEncodedStrip(t_.tif(), blk_indx, data, (tsize_t)-1) <= 0)
834 {
835 delete[] data;
836 return view;
837 }
838 this->copy_byte_block(data, encoded_block_size, buf);
839 delete[] data;
840 if (h_->need_byte_swap())
841 endian_swap(reinterpret_cast<vxl_byte *>(buf->data()), encoded_block_size, expanded_sample_bytes);
842 return this->fill_block_from_strip(buf);
843 }
844 else if (h_->is_striped() && h_->planar_config.val == 2)
845 {
846 // planes are storted in multiple strips (n_planes) for planar_config == 2
847 // the layout of the file is sequential by band (plane)
848 // b0 ---- ... ---- b0|b1 ---- ... ---- b1|b2 ---- ... ---- b2| ... |b_np_1 ---- ... ---- b_np-1|
849 // |strip 0|srip 1|... |strip_spp|... |strip_2*spp|... |strip_(np-1)*spp| ...
850 //
851 // b0 -> b_np-1 - bands 0 through band np-1;
852 // np - number of planes, spp - number of strips per plane
853 //
854 size_t nplanes = h_->nplanes;
855 size_t strip_data_size = encoded_block_size / nplanes;
856 size_t n_rows = h_->image_length.val;
857 size_t rows_per_strip = h_->rows_per_strip.val;
858 size_t strips_per_plane = n_rows / rows_per_strip;
859 if (strips_per_plane * rows_per_strip < n_rows)
860 strips_per_plane++;
861 size_t bytes_per_row = encoded_block_size / rows_per_strip;
862 size_t samples_per_pixel = h_->samples_per_pixel.val; // same as nplanes
863 size_t bytes_per_row_per_sample = bytes_per_row / samples_per_pixel;
864 size_t ni = h_->image_width.val; // pixels per row
865 size_t bytes_per_pixel = bytes_per_row / ni;
866 size_t bytes_per_sample = h_->bytes_per_sample();
867
868 // hold the strips extracted from each plane section of the file
869 std::vector<vxl_byte *> strip_plane_data(nplanes);
870
871 // read the multiple strips - one from each plane in the file
872 for (size_t s = 0; s < samples_per_pixel; ++s)
873 {
874 strip_plane_data[s] = new vxl_byte[strip_data_size];
875 size_t strip_indx = blk_indx + s * strips_per_plane;
876 size_t strip_size = TIFFReadEncodedStrip(t_.tif(), strip_indx, strip_plane_data[s], (tsize_t)-1);
877 if (strip_size <= 0) // if the read fails, bail--
878 {
879 for (size_t d = 0; d <= s; ++d)
880 delete[] strip_plane_data[d];
881 std::cout << "Error in reading tiff strip - " << strip_size << " bytes returned instead of " << strip_data_size
882 << std::endl;
883 return view;
884 }
885 }
886 // the start of block buffer to be filled from the cached strips
887 auto * buf_adr = reinterpret_cast<vxl_byte *>(buf->data());
888
889 // iterate over rows of the band strips and interleave bands as:
890 // |b0|b1|..b_np-1||b0|b1|..b_np-1||b0|b1|..b_np-1||b0|b1|..b_np-1|
891 // row r | pix 0 || pix1 || pix2 ... || pix (ni-1)
892 // where np is number of samples (planes) per pixel, ni pixels per row
893 //
894 for (size_t r = 0; r < rows_per_strip; ++r)
895 {
896 size_t rb_off = r * bytes_per_row, rs_off = r * bytes_per_row_per_sample;
897 for (size_t i = 0; i < ni; ++i)
898 {
899 size_t ib_off = i * bytes_per_pixel, is_off = i * bytes_per_sample;
900 for (size_t s = 0; s < samples_per_pixel; ++s)
901 {
902 size_t sb_off = s * bytes_per_sample;
903 for (size_t b = 0; b < bytes_per_sample; ++b)
904 {
905 size_t buf_off = rb_off + ib_off + sb_off + b;
906 size_t strip_off = rs_off + is_off + b;
907 *(buf_adr + buf_off) = *(strip_plane_data[s] + strip_off);
908 }
909 }
910 }
911 }
912 // delete the chached strips
913 for (size_t p = 0; p < nplanes; ++p)
914 delete[] strip_plane_data[p];
915
916 // might need to correct an endian mismatch
917 if (h_->need_byte_swap())
918 endian_swap(reinterpret_cast<vxl_byte *>(buf->data()), encoded_block_size, expanded_sample_bytes);
919
920 // transfer the buffer to the block view
921 return this->fill_block_from_strip(buf);
922 }
923 return view;
924 }
925
926 // decode tiles: the tile is a contiguous raster scan of potentially
927 // interleaved samples. This is an easy case since the tile is a
928 // contiguous raster scan.
929 vil_image_view_base_sptr
fill_block_from_tile(vil_memory_chunk_sptr const & buf) const930 vil_tiff_image::fill_block_from_tile(vil_memory_chunk_sptr const & buf) const
931 {
932 vil_image_view_base_sptr view = nullptr;
933
934 // the size of the buffer when expanded to byte representation
935 unsigned samples_per_block = this->samples_per_block();
936 assert(samples_per_block > 0);
937
938 vil_pixel_format fmt = vil_pixel_format_component_format(h_->pix_fmt);
939 view = view_from_buffer(fmt, buf, samples_per_block, h_->bits_per_sample.val);
940 return view;
941 }
942
943 // decode strips. The strip is somewhat different from the tile in that
944 // it is organized around scan lines. If bits_per_pixel is not an integral
945 // number of bytes then the last packed byte in the scan line will be only
946 // partially filled. The header function, bytes_per_line() gives the actual
947 // size of a scan line in the packed strip. The total size of the strip
948 // in bytes is normally size_block_j()*bytes_per_line() but the last strip
949 // may be truncated.
950 vil_image_view_base_sptr
fill_block_from_strip(vil_memory_chunk_sptr const & buf) const951 vil_tiff_image::fill_block_from_strip(vil_memory_chunk_sptr const & buf) const
952 {
953 vil_image_view_base_sptr view = nullptr;
954 vxl_uint_32 tl = size_block_j();
955
956 unsigned bpl = h_->bytes_per_line();
957 unsigned bytes_per_strip = h_->bytes_per_strip();
958 unsigned lines_per_strip = bytes_per_strip / bpl;
959 vil_pixel_format fmt = vil_pixel_format_component_format(h_->pix_fmt);
960 unsigned expanded_bytes_per_sample = vil_pixel_format_sizeof_components(fmt);
961 unsigned spl = h_->samples_per_line();
962 unsigned bytes_expanded_line = spl * expanded_bytes_per_sample;
963 // note here we make the last strip a full sized block to avoid
964 // the messyness of multiple block sizes
965 unsigned expanded_bytes_per_strip = tl * bytes_expanded_line;
966
967 // pointer into the input packed strip buffer
968 auto * buf_ptr = reinterpret_cast<vxl_byte *>(buf->data());
969
970 // buffer for each scan line
971 vil_memory_chunk_sptr line_buf = new vil_memory_chunk(bpl, fmt);
972
973 // a buffer of zeros for filling partial strips to tile size
974 vil_memory_chunk_sptr zero_buf = new vil_memory_chunk(bytes_expanded_line, fmt);
975 auto * zero_ptr = reinterpret_cast<vxl_byte *>(zero_buf->data());
976 for (unsigned i = 0; i < bytes_expanded_line; ++i)
977 zero_ptr[i] = 0;
978
979 // buffer for the final unpacked output block
980 vil_memory_chunk_sptr block_buf = new vil_memory_chunk(expanded_bytes_per_strip, fmt);
981 auto * block_ptr = reinterpret_cast<vxl_byte *>(block_buf->data());
982 // read scan lines from the strip and paste into the block
983 for (unsigned j = 0; j < tl; ++j, buf_ptr += bpl, block_ptr += bytes_expanded_line)
984 {
985 if (j < lines_per_strip)
986 {
987 // get a row from the input buffer
988 copy_byte_block(buf_ptr, bpl, line_buf);
989 vil_memory_chunk_sptr out_line_buf;
990 switch (fmt)
991 {
992 #define GET_LINE_CASE(FORMAT, T) \
993 case FORMAT: \
994 out_line_buf = tiff_maybe_byte_align_data<T>(line_buf, spl, h_->bits_per_sample.val, bytes_expanded_line); \
995 break
996 GET_LINE_CASE(VIL_PIXEL_FORMAT_BYTE, vxl_byte);
997 GET_LINE_CASE(VIL_PIXEL_FORMAT_SBYTE, vxl_sbyte);
998 #if VXL_HAS_INT_64
999 GET_LINE_CASE(VIL_PIXEL_FORMAT_UINT_64, vxl_uint_64);
1000 GET_LINE_CASE(VIL_PIXEL_FORMAT_INT_64, vxl_int_64);
1001 #endif
1002 GET_LINE_CASE(VIL_PIXEL_FORMAT_UINT_32, vxl_uint_32);
1003 GET_LINE_CASE(VIL_PIXEL_FORMAT_INT_32, vxl_int_32);
1004 GET_LINE_CASE(VIL_PIXEL_FORMAT_UINT_16, vxl_uint_16);
1005 GET_LINE_CASE(VIL_PIXEL_FORMAT_INT_16, vxl_int_16);
1006 GET_LINE_CASE(VIL_PIXEL_FORMAT_BOOL, bool);
1007 GET_LINE_CASE(VIL_PIXEL_FORMAT_FLOAT, float);
1008 GET_LINE_CASE(VIL_PIXEL_FORMAT_DOUBLE, double);
1009 #undef GET_LINE_CASE
1010 default:
1011 assert(!"Unknown vil data type in tiff file format");
1012 break;
1013 }
1014 // now we have the unpacked scan line in out_buf so copy to the view
1015 // buffer.
1016 auto * out_line_buf_ptr = reinterpret_cast<vxl_byte *>(out_line_buf->data());
1017
1018 std::memcpy(block_ptr, out_line_buf_ptr, bytes_expanded_line);
1019 }
1020 else
1021 std::memcpy(block_ptr, zero_ptr, bytes_expanded_line);
1022 }
1023 return this->view_from_buffer(fmt, block_buf, spl * tl, expanded_bytes_per_sample * 8);
1024 }
1025
1026 void
pad_block_with_zeros(unsigned ioff,unsigned joff,unsigned iclip,unsigned jclip,unsigned bytes_per_pixel,vxl_byte * block_buf) const1027 vil_tiff_image::pad_block_with_zeros(unsigned ioff,
1028 unsigned joff,
1029 unsigned iclip,
1030 unsigned jclip,
1031 unsigned bytes_per_pixel,
1032 vxl_byte * block_buf) const
1033 {
1034 unsigned jstep = size_block_i() * bytes_per_pixel;
1035 unsigned row_start = ioff * bytes_per_pixel;
1036 unsigned bptr = 0;
1037 // fill leading part with zeroes
1038 if (ioff > 0 || joff > 0)
1039 for (unsigned j = 0; j < joff - 1; ++j)
1040 {
1041 unsigned row_ptr = row_start;
1042 for (unsigned i = 0; i < ioff - 1; ++i)
1043 {
1044 for (unsigned p = 0; p < nplanes(); ++p)
1045 *(block_buf + bptr + row_ptr + p) = 0;
1046 row_ptr += bytes_per_pixel;
1047 }
1048 bptr += jstep;
1049 }
1050 bptr = jstep * jclip;
1051 row_start = iclip * bytes_per_pixel;
1052 if (iclip > 0 || jclip > 0)
1053 for (unsigned j = jclip; j < size_block_j(); ++j)
1054 {
1055 unsigned row_ptr = row_start;
1056 for (unsigned i = iclip; i < size_block_i(); ++i)
1057 {
1058 for (unsigned p = 0; p < nplanes(); ++p)
1059 *(block_buf + bptr + row_ptr + p) = 0;
1060 row_ptr += bytes_per_pixel;
1061 }
1062 bptr += jstep;
1063 }
1064 }
1065
1066 void
fill_block_from_view(unsigned bi,unsigned bj,unsigned i0,unsigned j0,unsigned ioff,unsigned joff,unsigned iclip,unsigned jclip,const vil_image_view_base & im,vxl_byte * & block_buf)1067 vil_tiff_image::fill_block_from_view(unsigned bi,
1068 unsigned bj,
1069 unsigned i0,
1070 unsigned j0,
1071 unsigned ioff,
1072 unsigned joff,
1073 unsigned iclip,
1074 unsigned jclip,
1075 const vil_image_view_base & im,
1076 vxl_byte *& block_buf)
1077 {
1078 unsigned bytes_per_sample = h_->bytes_per_sample();
1079 unsigned bytes_per_pixel = bytes_per_sample * nplanes();
1080 unsigned sbi = size_block_i(), sbj = size_block_j();
1081 unsigned bytes_per_block = bytes_per_pixel * sbi * sbj;
1082 unsigned view_i0 = bi * sbi - i0, view_j0 = bj * sbj - j0;
1083 unsigned block_jstep = sbi * bytes_per_pixel;
1084 #if 0
1085 //Causes warnings. Leave here to document default values
1086 unsigned view_istep = 1, view_jstep = im.ni()*bytes_per_pixel, view_pstep = 1;
1087 #endif
1088 std::ptrdiff_t view_istep, view_jstep, view_pstep;
1089 vxl_byte * view_buf;
1090 // Cast the pixel type and reinterpret upper_left_ptr as a byte array.
1091 switch (h_->pix_fmt)
1092 {
1093 #define GET_VIEW_PTR(FORMAT, T) \
1094 case FORMAT: { \
1095 vil_image_view<T> view = static_cast<const vil_image_view<T> &>(im); \
1096 view_istep = view.istep(); \
1097 view_jstep = view.jstep(); \
1098 view_pstep = view.planestep(); \
1099 view_buf = reinterpret_cast<vxl_byte *>(view.top_left_ptr()); \
1100 } \
1101 break
1102 GET_VIEW_PTR(VIL_PIXEL_FORMAT_BYTE, vxl_byte);
1103 GET_VIEW_PTR(VIL_PIXEL_FORMAT_SBYTE, vxl_sbyte);
1104 #if VXL_HAS_INT_64
1105 GET_VIEW_PTR(VIL_PIXEL_FORMAT_UINT_64, vxl_uint_64);
1106 GET_VIEW_PTR(VIL_PIXEL_FORMAT_INT_64, vxl_int_64);
1107 #endif
1108 GET_VIEW_PTR(VIL_PIXEL_FORMAT_UINT_32, vxl_uint_32);
1109 GET_VIEW_PTR(VIL_PIXEL_FORMAT_INT_32, vxl_int_32);
1110 GET_VIEW_PTR(VIL_PIXEL_FORMAT_UINT_16, vxl_uint_16);
1111 GET_VIEW_PTR(VIL_PIXEL_FORMAT_INT_16, vxl_int_16);
1112 GET_VIEW_PTR(VIL_PIXEL_FORMAT_BOOL, bool);
1113 GET_VIEW_PTR(VIL_PIXEL_FORMAT_FLOAT, float);
1114 GET_VIEW_PTR(VIL_PIXEL_FORMAT_DOUBLE, double);
1115 #undef GET_VIEW_PTR
1116 default:
1117 assert(!"Unknown vil data type.");
1118 return;
1119 }
1120 // initial index into block buffer
1121 unsigned bptr = joff * block_jstep;
1122 unsigned ibstart = ioff * bytes_per_pixel;
1123 std::ptrdiff_t vistp = view_istep * bytes_per_sample;
1124 std::ptrdiff_t vjstp = view_jstep * bytes_per_sample;
1125 std::ptrdiff_t vpstp = view_pstep * bytes_per_sample;
1126 // initial index into view buffer
1127 // note that it is necessary to add the offset to the start of the
1128 // current block within the view, (view_i0, view_j0)
1129 std::ptrdiff_t vptr = (view_j0 + joff) * vjstp;
1130 unsigned ivstart = (view_i0 + ioff) * bytes_per_pixel;
1131 for (unsigned j = joff; j < jclip; ++j)
1132 {
1133 std::ptrdiff_t vrow_ptr = ivstart;
1134 std::ptrdiff_t brow_ptr = ibstart;
1135 for (unsigned i = ioff; i < iclip; ++i)
1136 {
1137 std::ptrdiff_t bpptr = 0, vpptr = 0;
1138 for (unsigned p = 0; p < nplanes(); ++p)
1139 {
1140 for (unsigned b = 0; b < bytes_per_sample; ++b)
1141 *(block_buf + bptr + brow_ptr + bpptr + b) = *(view_buf + vptr + vrow_ptr + vpptr + b);
1142 bpptr += bytes_per_sample;
1143 vpptr += vpstp;
1144 }
1145 brow_ptr += bytes_per_pixel;
1146 vrow_ptr += vistp;
1147 }
1148 bptr += block_jstep;
1149 vptr += vjstp;
1150 }
1151
1152 // handle the case of bool (other packed formats not supported for writing)
1153 if (this->pixel_format() == VIL_PIXEL_FORMAT_BOOL)
1154 {
1155 unsigned outsize = (bytes_per_block + 7 * sizeof(bool)) / (8 * sizeof(bool));
1156 auto * outbuf = new vxl_byte[outsize];
1157 this->bitpack_block(bytes_per_block, block_buf, outbuf);
1158 delete[] block_buf;
1159 block_buf = outbuf; // bytes_per_block=outsize;
1160 }
1161 }
1162
1163 bool
write_block_to_file(unsigned bi,unsigned bj,unsigned block_size_bytes,vxl_byte * block_buf)1164 vil_tiff_image::write_block_to_file(unsigned bi, unsigned bj, unsigned block_size_bytes, vxl_byte * block_buf)
1165 {
1166 unsigned blk_indx = this->block_index(bi, bj);
1167 if (h_->is_tiled())
1168 return TIFFWriteEncodedTile(t_.tif(), blk_indx, block_buf, block_size_bytes) > 0;
1169 if (h_->is_striped())
1170 return TIFFWriteEncodedStrip(t_.tif(), blk_indx, block_buf, block_size_bytes) > 0;
1171 return false;
1172 }
1173
1174 // Just support packing of bool data for now
1175 // ultimately we need the opposite of maybe_byte_align_data
1176 void
bitpack_block(unsigned bytes_per_block,const vxl_byte * in_block_buf,vxl_byte * out_block_buf)1177 vil_tiff_image::bitpack_block(unsigned bytes_per_block, const vxl_byte * in_block_buf, vxl_byte * out_block_buf)
1178 {
1179 unsigned bytes_per_bool = sizeof(bool);
1180 auto * bl = new vxl_byte[bytes_per_bool];
1181 unsigned bitctr = 0;
1182 unsigned outctr = 0;
1183 vxl_byte packed_byte = 0;
1184 for (unsigned i = 0; i < bytes_per_block;)
1185 {
1186 // test for a completed packed byte
1187 if (bitctr == 8)
1188 {
1189 bitctr = 0;
1190 out_block_buf[outctr] = packed_byte;
1191 packed_byte = 0;
1192 ++outctr;
1193 }
1194 // pack a bool into the next bit
1195 for (unsigned b = 0; b < bytes_per_bool; ++b)
1196 bl[b] = *(in_block_buf + i + b);
1197 bool blv = *(reinterpret_cast<bool *>(bl));
1198 if (blv)
1199 packed_byte |= vxl_byte(1 << (7 - bitctr)); // set a "1"
1200 else
1201 packed_byte &= vxl_byte(~(1 << (7 - bitctr))); // set a "0"
1202 ++bitctr;
1203
1204 i += bytes_per_bool;
1205 if (i >= bytes_per_block) // output last (partial) byte
1206 out_block_buf[outctr] = packed_byte;
1207 }
1208 delete[] bl;
1209 }
1210
1211 // an internal form of put_block for convenience
1212 // write the indicated block to file, padding with zeros if necessary
1213 // image view im is an arbitrary region of image that has to be decomposed into
1214 // blocks. The resource is written with zeros if the input view doesn't
1215 // correspond to exact block boundaries. Subsequent put_view calls could
1216 // fill in the missing image data.
1217 bool
put_block(unsigned bi,unsigned bj,unsigned i0,unsigned j0,const vil_image_view_base & im)1218 vil_tiff_image::put_block(unsigned bi, unsigned bj, unsigned i0, unsigned j0, const vil_image_view_base & im)
1219 {
1220 // Get the block offset and clipping parameters
1221
1222 // ioff and joff are the offsets within a block to the start of valid data
1223 unsigned ioff = 0, joff = 0;
1224 unsigned sbi = size_block_i(), sbj = size_block_j();
1225 unsigned iclip = sbi, jclip = sbj;
1226 // column offset into block. fill [0->ioff-1]
1227 if (bi * sbi < i0 && (bi + 1) * sbi > i0)
1228 if (!block_i_offset(bi, i0, ioff))
1229 return false;
1230 // row offset into block fill [0->joff-1]
1231 if (bj * sbj < j0 && (bj + 1) * sbj > j0)
1232 if (!block_j_offset(bj, j0, joff))
1233 return false;
1234
1235 // iclip and jclip are the start of invalid data at the right and
1236 // bottom of partially filled blocks
1237
1238 // right block margin to be padded [iclip -> size_block_i()-1]
1239 if ((bi + 1) * sbi > (im.ni() + i0))
1240 {
1241 iclip = (i0 + im.ni()) - bi * sbi;
1242 if (iclip > sbi)
1243 return false;
1244 }
1245
1246 // bottom block margin to be padded [jclip -> size_block_j()-1]
1247 if ((bj + 1) * sbj > (im.nj() + j0))
1248 {
1249 jclip = (j0 + im.nj()) - bj * sbj;
1250 if (jclip > sbj)
1251 return false;
1252 }
1253 unsigned bps = h_->bytes_per_sample();
1254 unsigned bytes_per_pixel = bps * nplanes();
1255
1256 unsigned bytes_per_block = bytes_per_pixel * sbi * sbj;
1257
1258
1259 // the data buffer for the block
1260 auto * block_buf = new vxl_byte[bytes_per_block];
1261
1262 this->pad_block_with_zeros(ioff, joff, iclip, jclip, bytes_per_pixel, block_buf);
1263
1264
1265 this->fill_block_from_view(bi, bj, i0, j0, ioff, joff, iclip, jclip, im, block_buf);
1266 // write the block to the tiff file
1267 bool good_write = write_block_to_file(bi, bj, bytes_per_block, block_buf);
1268 delete[] block_buf;
1269 return good_write;
1270 }
1271
1272 bool
put_view(const vil_image_view_base & im,unsigned i0,unsigned j0)1273 vil_tiff_image::put_view(const vil_image_view_base & im, unsigned i0, unsigned j0)
1274 {
1275 if (!vil_image_resource::view_fits(im, i0, j0))
1276 {
1277 vil_exception_warning(vil_exception_out_of_bounds("vil_tiff_image::put_view"));
1278 return false;
1279 }
1280
1281 unsigned tw = size_block_i(), tl = size_block_j();
1282 if (tw == 0 || tl == 0)
1283 return false;
1284 unsigned bi_start = i0 / tw, bi_end = (i0 + im.ni() - 1) / tw;
1285 unsigned bj_start = j0 / tl, bj_end = (j0 + im.nj() - 1) / tl;
1286 for (unsigned bi = bi_start; bi <= bi_end; ++bi)
1287 for (unsigned bj = bj_start; bj <= bj_end; ++bj)
1288 if (!this->put_block(bi, bj, i0, j0, im))
1289 return false;
1290 return true;
1291 }
1292
1293 // The virtual put_block method. In this case the view is a complete block
1294 bool
put_block(unsigned block_index_i,unsigned block_index_j,const vil_image_view_base & blk)1295 vil_tiff_image::put_block(unsigned block_index_i, unsigned block_index_j, const vil_image_view_base & blk)
1296 {
1297 if (blk.ni() == 0 || blk.nj() == 0)
1298 return false;
1299 unsigned sbi = this->size_block_i(), sbj = this->size_block_j();
1300 unsigned bps = h_->bytes_per_sample();
1301 unsigned bytes_per_pixel = bps * nplanes();
1302
1303 unsigned bytes_per_block = bytes_per_pixel * sbi * sbj;
1304
1305 // the data buffer for the block
1306 auto * block_buf = new vxl_byte[bytes_per_block];
1307
1308 this->fill_block_from_view(0, 0, 0, 0, 0, 0, sbi, sbj, blk, block_buf);
1309
1310 // write the block to the tiff file
1311 bool good_write = write_block_to_file(block_index_i, block_index_j, bytes_per_block, block_buf);
1312 delete[] block_buf;
1313 return good_write;
1314 }
1315
1316 // Begin pyramid resource
1317 static bool
level_compare(tiff_pyramid_level * const l1,tiff_pyramid_level * const l2)1318 level_compare(tiff_pyramid_level * const l1, tiff_pyramid_level * const l2)
1319 {
1320 assert(l1 && l2);
1321 return l1->ni_ > l2->ni_;
1322 }
1323
1324 //: Assumes that the image in level 0 is the largest
1325 void
normalize_scales()1326 vil_tiff_pyramid_resource::normalize_scales()
1327 {
1328 unsigned nlevels = this->nlevels();
1329 if (nlevels == 0)
1330 return;
1331 levels_[0]->scale_ = 1.0f;
1332 if (nlevels == 1)
1333 return;
1334 auto ni0 = static_cast<float>(levels_[0]->ni_);
1335 for (unsigned i = 1; i < nlevels; ++i)
1336 levels_[i]->scale_ = static_cast<float>(levels_[i]->ni_) / ni0;
1337 }
1338
1339 //:find the level closest to the specified scale
1340 tiff_pyramid_level *
closest(const float scale) const1341 vil_tiff_pyramid_resource::closest(const float scale) const
1342 {
1343 unsigned nlevels = this->nlevels();
1344 if (nlevels == 0)
1345 return nullptr;
1346 if (nlevels == 1)
1347 return levels_[0];
1348 float mind = 1.0e08f; // huge scale;
1349 unsigned lmin = 0;
1350 for (unsigned i = 0; i < nlevels; ++i)
1351 {
1352 float ds = std::fabs(scale - levels_[i]->scale_);
1353 if (ds < mind)
1354 {
1355 mind = ds;
1356 lmin = i;
1357 }
1358 }
1359 tiff_pyramid_level * pl = levels_[lmin];
1360 if (pl)
1361 pl->cur_level_ = lmin;
1362 return pl;
1363 }
1364
vil_tiff_pyramid_resource()1365 vil_tiff_pyramid_resource::vil_tiff_pyramid_resource() : t_(nullptr) {}
1366
vil_tiff_pyramid_resource(tif_smart_ptr const & t,bool read)1367 vil_tiff_pyramid_resource::vil_tiff_pyramid_resource(tif_smart_ptr const & t, bool read)
1368 : read_(read)
1369 , t_(t)
1370 {
1371 bool trace = false;
1372 if (!read)
1373 return;
1374 // for reading we need to set up the levels
1375 while (true)
1376 {
1377 vil_tiff_header h(t_.tif());
1378 if (trace)
1379 std::cerr << "In vil_tiff_pyramid_resource constructor"
1380 << " constructed header\n"
1381 << "n-levels = " << this->nlevels() << '\n';
1382 auto * pl = new tiff_pyramid_level(this->nlevels(), h.image_width.val, h.image_length.val, h.nplanes, h.pix_fmt);
1383 levels_.push_back(pl);
1384 if (trace)
1385 std::cerr << "In vil_tiff_pyramid_resource constructor"
1386 << " constructed level\n";
1387 int status = TIFFReadDirectory(t_.tif());
1388 if (trace)
1389 std::cerr << "In vil_tiff_pyramid_resource constructor"
1390 << " Read new directory\n";
1391
1392 if (!status)
1393 break;
1394 }
1395 if (trace)
1396 std::cerr << "In vil_tiff_pyramid_resource constructor"
1397 << " Begin sorting\n";
1398 // sort the pyramid
1399 std::sort(levels_.begin(), levels_.end(), level_compare);
1400 // normalize the scales
1401 this->normalize_scales();
1402 }
1403
~vil_tiff_pyramid_resource()1404 vil_tiff_pyramid_resource::~vil_tiff_pyramid_resource()
1405 {
1406 for (unsigned L = 0; L < this->nlevels(); ++L)
1407 delete levels_[L];
1408 }
1409
1410 //:Get a partial view from the image from a specified pyramid level
1411 vil_image_view_base_sptr
get_copy_view(unsigned i0,unsigned n_i,unsigned j0,unsigned n_j,unsigned level) const1412 vil_tiff_pyramid_resource::get_copy_view(unsigned i0, unsigned n_i, unsigned j0, unsigned n_j, unsigned level) const
1413 {
1414 unsigned nl = this->nlevels();
1415 if (level >= nl)
1416 return vil_image_view_base_sptr();
1417 vil_image_resource_sptr resc = this->get_resource(level);
1418 // scale input coordinates to the scale of the level
1419 float scale = levels_[level]->scale_;
1420 float fi0 = std::floor(scale * i0), fj0 = std::floor(scale * j0);
1421 float fni = std::floor(scale * n_i), fnj = std::floor(scale * n_j);
1422 auto si0 = static_cast<unsigned>(fi0);
1423 auto sj0 = static_cast<unsigned>(fj0);
1424 auto sni = static_cast<unsigned>(fni);
1425 if (sni == 0)
1426 sni = 1; // can't have less than one pixel
1427 auto snj = static_cast<unsigned>(fnj);
1428 if (snj == 0)
1429 snj = 1; // can't have less than one pixel
1430 vil_image_view_base_sptr view = resc->get_copy_view(si0, sni, sj0, snj);
1431 #if 0 // DON'T NEED CLEAR?
1432 resc->clear_TIFF();
1433 #endif
1434 return view;
1435 }
1436
1437 //:Get a partial view from the image in the pyramid closest to scale.
1438 // The origin and size parameters are in the coordinate system
1439 // of the base image. The scale factor is with respect to the base
1440 // image (base scale = 1.0).
1441 vil_image_view_base_sptr
get_copy_view(unsigned i0,unsigned n_i,unsigned j0,unsigned n_j,const float scale,float & actual_scale) const1442 vil_tiff_pyramid_resource::get_copy_view(unsigned i0,
1443 unsigned n_i,
1444 unsigned j0,
1445 unsigned n_j,
1446 const float scale,
1447 float & actual_scale) const
1448 {
1449 // Get the closest scale
1450 tiff_pyramid_level * pl = this->closest(scale);
1451 if (!pl)
1452 return nullptr;
1453 actual_scale = pl->scale_;
1454 return this->get_copy_view(i0, n_i, j0, n_j, pl->cur_level_);
1455 }
1456
1457 //: Put the data in this view back into the image source at specified level.
1458 // Only can be written once.
1459 bool
put_resource(vil_image_resource_sptr const & ir)1460 vil_tiff_pyramid_resource::put_resource(vil_image_resource_sptr const & ir)
1461 {
1462 unsigned level = this->nlevels();
1463 unsigned ni = ir->ni(), nj = ir->nj();
1464 unsigned nplanes = ir->nplanes();
1465 vil_pixel_format fmt = ir->pixel_format();
1466 vil_blocked_image_resource_sptr bir = blocked_image_resource(ir);
1467 unsigned sbi = 0, sbj = 0;
1468 if (bir)
1469 {
1470 sbi = bir->size_block_i();
1471 sbj = bir->size_block_j();
1472 }
1473 // setup the image header for the level
1474 auto * h = new vil_tiff_header(t_.tif(), ni, nj, nplanes, fmt, sbi, sbj);
1475
1476 /* We are writing single page of the multipage file */
1477 TIFFSetField(t_.tif(), TIFFTAG_SUBFILETYPE, FILETYPE_PAGE);
1478 /* Set the page number */
1479 TIFFSetField(t_.tif(), TIFFTAG_PAGENUMBER, level, 3);
1480 auto * ti = new vil_tiff_image(t_, h, level);
1481 vil_image_resource_sptr resc = ti;
1482 if (!vil_copy_deep(ir, resc))
1483 return false;
1484 #if 0 // DON'T NEED CLEAR?
1485 ti->clear_TIFF();
1486 #endif
1487 auto * pl = new tiff_pyramid_level((unsigned int)(levels_.size()), ni, nj, nplanes, fmt);
1488 levels_.push_back(pl);
1489 int status = TIFFWriteDirectory(t_.tif());
1490 return status == 1;
1491 }
1492 //: returns the pyramid resource at the specified level
1493 vil_image_resource_sptr
get_resource(const unsigned level) const1494 vil_tiff_pyramid_resource::get_resource(const unsigned level) const
1495 {
1496 unsigned nl = this->nlevels();
1497 if (level >= nl)
1498 return nullptr;
1499 // setup the image header for the level
1500 unsigned header_index = levels_[level]->header_index_;
1501 // The status value should be checked here
1502 if (TIFFSetDirectory(t_.tif(), header_index) <= 0)
1503 return nullptr;
1504 auto * h = new vil_tiff_header(t_.tif());
1505 auto * i = new vil_tiff_image(t_, h, nl);
1506 i->set_index(header_index);
1507 return i;
1508 }
1509