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