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