core/vil/file_formats/vil_tiff.cxx
Go to the documentation of this file.
00001 //This is core/vil/file_formats/vil_tiff.cxx
00002 #include "vil_tiff.h"
00003 //:
00004 // \file
00005 // See vil_tiff.h for a description of this file.
00006 //
00007 // \author  awf@robots.ox.ac.uk
00008 //
00009 // \verbatim
00010 //  Modifications:
00011 //   2001-11-09 K.Y.McGaul  Use dflt value for orientation when it can't be read
00012 //   2005-12-xx J.L. Mundy  Essentially a complete rewrite to support blocking.
00013 //                          Cleaner struct: hdr params moved to vil_tiff_header
00014 // \endverbatim
00015 
00016 #include <vcl_cassert.h>
00017 #include <vcl_cstring.h>
00018 #include <vcl_iostream.h>
00019 #include <vcl_algorithm.h>
00020 #include <vcl_sstream.h>
00021 #include <vil/vil_stream.h>
00022 #include <vil/vil_property.h>
00023 #include <vil/vil_image_view.h>
00024 #include <vil/vil_memory_chunk.h>
00025 #include <vil/vil_copy.h>
00026 #include <vil/vil_image_list.h>
00027 #include "vil_tiff_header.h"
00028 #include <vil/vil_exception.h>
00029 //#define DEBUG
00030 
00031 // Constants
00032 char const* vil_tiff_format_tag = "tiff";
00033 
00034 static unsigned nimg(TIFF* tif)
00035 {
00036   if (!tif)
00037     return 0;
00038   TIFFSetDirectory(tif, 0);
00039   unsigned int dircount = 0;
00040   do {
00041     dircount++;
00042   } while (TIFFReadDirectory(tif));
00043   return dircount;
00044 }
00045 
00046 
00047 bool vil_tiff_file_format_probe(vil_stream* is)
00048 {
00049   // The byte ordering in a TIFF image (usually) depends on the byte-order
00050   // of the writing host. The header is always 4 bytes.
00051 
00052   char hdr[4];
00053   unsigned read = (unsigned)is->read(hdr, sizeof hdr);
00054   if (read < sizeof hdr)
00055     return false;
00056 
00057   // First two bytes specify the file byte-order (0x4D4D=big, 0x4949=little).
00058   // Second two bytes specify the TIFF version (we expect 0x2A for some reason?).
00059   // So,
00060   //   0x4D 0x4D 0x2A 0x00
00061 
00062   // and
00063   //   0x49 0x49 0x00 0x2A
00064   // are invalid TIFF headers.
00065   if (hdr[0]==0x4D && hdr[1]==0x4D &&
00066       hdr[2]==0x00 && hdr[3]==0x2A)
00067     return true;
00068 
00069   else if (hdr[0]==0x49 && hdr[1]==0x49 &&
00070            hdr[2]==0x2A && hdr[3]==0x00)
00071     return true;
00072 
00073   else if ( ((hdr[0]==0x4D && hdr[1]==0x4D) || (hdr[1]==0x49 && hdr[1]==0x49)) &&
00074             ((hdr[2]==0x00 && hdr[3]==0x2A) || (hdr[2]==0x2A && hdr[3]==0x00)) )  {
00075     vcl_cerr << __FILE__ ": suspicious TIFF header\n";
00076     return true; // allow it.
00077   }
00078 
00079   else
00080     return false;
00081 }
00082 
00083 struct tif_stream_structures
00084 {
00085   tif_stream_structures(vil_stream *vs_)
00086     : vs(vs_), filesize(0) /*, sample_format( SAMPLEFORMAT_VOID ), buf(0) */
00087   { if (vs) vs->ref(); }
00088 
00089   ~tif_stream_structures() { /* delete[] buf; */ if (vs) vs->unref(); }
00090 
00091   TIFF* tif;
00092   vil_stream* vs;
00093   vil_streampos filesize;
00094 };
00095 
00096 static tsize_t vil_tiff_readproc(thandle_t h, tdata_t buf, tsize_t n)
00097 {
00098   tif_stream_structures* p = (tif_stream_structures*)h;
00099   if (n > p->filesize) p->filesize= n;
00100   //there should be no problem with this case because n
00101   //is also of type tsize_t
00102   tsize_t ret = (tsize_t)p->vs->read(buf, n);
00103   return ret;
00104 }
00105 
00106 static tsize_t vil_tiff_writeproc(thandle_t h, tdata_t buf, tsize_t n)
00107 {
00108   tif_stream_structures* p = (tif_stream_structures*)h;
00109   //there should be no problem with this case because n
00110   //is also of type tsize_t
00111   tsize_t ret = (tsize_t)p->vs->write(buf, n);
00112   vil_streampos s = p->vs->tell();
00113   if (s > p->filesize)
00114     p->filesize = s;
00115   return ret;
00116 }
00117 
00118 static toff_t vil_tiff_seekproc(thandle_t h, toff_t offset, int whence)
00119 {
00120   tif_stream_structures* p = (tif_stream_structures*)h;
00121   if      (whence == SEEK_SET) p->vs->seek(offset);
00122   else if (whence == SEEK_CUR) p->vs->seek(p->vs->tell() + offset);
00123   else if (whence == SEEK_END) p->vs->seek(p->filesize + offset);
00124   vil_streampos s = p->vs->tell();
00125   if (s > p->filesize)
00126     p->filesize = s;
00127   return (toff_t)s;
00128 }
00129 
00130 static int vil_tiff_closeproc(thandle_t h)
00131 {
00132   tif_stream_structures* p = (tif_stream_structures*)h;
00133   p->vs->unref();
00134   p->vs = 0;
00135   delete p;
00136   return 0;
00137 }
00138 
00139 static toff_t vil_tiff_sizeproc(thandle_t)
00140 {
00141   // TODO
00142 #ifdef DEBUG
00143   vcl_cerr << "Warning: vil_tiff_sizeproc() not yet implemented\n";
00144 #endif
00145   return (toff_t)(-1); // could be unsigned - avoid compiler warning
00146 }
00147 
00148 static int vil_tiff_mapfileproc(thandle_t, tdata_t*, toff_t*)
00149 {
00150   // TODO: Add mmap support to vil_tiff_mapfileproc
00151 #ifdef DEBUG
00152   vcl_cerr << "Warning: mmap support not yet in vil_tiff_mapfileproc()\n";
00153 #endif
00154   return 0;
00155 }
00156 
00157 static void vil_tiff_unmapfileproc(thandle_t, tdata_t, toff_t)
00158 {
00159 }
00160 
00161 
00162 static TIFF* open_tiff(tif_stream_structures* tss, const char* mode)
00163 {
00164   tss->vs->seek(0L);
00165   TIFF* tiff = TIFFClientOpen("unknown filename",
00166                               mode, // read, enable strip chopping
00167                               (thandle_t)tss,
00168                               vil_tiff_readproc, vil_tiff_writeproc,
00169                               vil_tiff_seekproc, vil_tiff_closeproc,
00170                               vil_tiff_sizeproc,
00171                               vil_tiff_mapfileproc, vil_tiff_unmapfileproc);
00172 
00173   if (!tiff)
00174     return 0;
00175   else
00176     return tiff;
00177 }
00178 
00179 vil_image_resource_sptr vil_tiff_file_format::make_input_image(vil_stream* is)
00180 {
00181   if (!vil_tiff_file_format_probe(is))
00182     return 0;
00183   tif_stream_structures* tss = new tif_stream_structures(is);
00184 
00185   tss->tif = open_tiff(tss, "rC");
00186 
00187   if (!tss->tif)
00188     return 0;
00189   vil_tiff_header* h = new vil_tiff_header(tss->tif);
00190 
00191   if (!h->format_supported)
00192   {
00193     TIFFClose(tss->tif);
00194     delete h;
00195     return 0;
00196   }
00197   unsigned n = nimg(tss->tif);
00198   tif_smart_ptr tif_sptr = new tif_ref_cnt(tss->tif);
00199   return new vil_tiff_image(tif_sptr, h, n);
00200 }
00201 
00202 vil_pyramid_image_resource_sptr
00203 vil_tiff_file_format::make_input_pyramid_image(char const* file)
00204 {
00205   bool trace = false;
00206   if (vil_image_list::vil_is_directory(file))
00207     return 0;
00208   TIFF* in  = TIFFOpen(file, "rC");
00209   if (!in)
00210     return 0;
00211   bool open_for_reading = true;
00212   if (trace) // find test failure
00213     vcl_cerr << "make_input_pyramid_image::opening multi-image tiff pyramid resource\n";
00214   tif_smart_ptr tif_sptr = new tif_ref_cnt(in);
00215   vil_pyramid_image_resource_sptr pyr =
00216     new vil_tiff_pyramid_resource(tif_sptr, open_for_reading);
00217   if (pyr->nlevels()<=1)
00218     return 0;
00219   else
00220     return pyr;
00221 }
00222 
00223 static vcl_string level_filename(vcl_string& directory, vcl_string& filename,
00224                                  unsigned level)
00225 {
00226   vcl_string slash;
00227 
00228 #ifdef VCL_WIN32
00229   slash =  "\\";
00230 #else
00231   slash = "/";
00232 #endif
00233   vcl_stringstream cs;
00234   cs << level;
00235   return directory + slash + filename + cs.str();
00236 }
00237 
00238 vil_pyramid_image_resource_sptr vil_tiff_file_format::
00239 make_pyramid_image_from_base(char const* file,
00240                              vil_image_resource_sptr const& base_image,
00241                              unsigned nlevels,
00242                              char const* temp_dir)
00243 {
00244   {//scope for writing the resources
00245     vil_pyramid_image_resource_sptr pyr = make_pyramid_output_image(file);
00246     pyr->put_resource(base_image);
00247     //Create the other pyramid levels
00248     {//scope for resource files
00249       vcl_string d = temp_dir;
00250       vcl_string fn = "tempR";
00251       vil_image_resource_sptr image = base_image;
00252       for (unsigned L = 1; L<nlevels; ++L)
00253       {
00254         vcl_cout << "Decimating Level " << L << vcl_endl;
00255         vcl_string full_filename = level_filename(d, fn, L) + ".tif";
00256         image =
00257           vil_pyramid_image_resource::decimate(image, full_filename.c_str());
00258       }
00259     }//end program scope to close resource files
00260 
00261     //reopen them for reading
00262     {//scope for il resources
00263       vil_image_list il(temp_dir);
00264       vcl_vector<vil_image_resource_sptr> rescs = il.resources();
00265       for (vcl_vector<vil_image_resource_sptr>::iterator rit = rescs.begin();
00266            rit != rescs.end(); ++rit)
00267         pyr->put_resource(*rit);
00268     }//close il resources
00269   }//close pyr
00270 
00271   //clean up the temporary directory
00272   vil_image_list vl(temp_dir);
00273   if (!vl.clean_directory())
00274   {
00275     vcl_cout <<"Warning: In vil_tiff::make_pyramid_from_base(..) -"
00276              << " temporary directory not cleaned\n";
00277   }
00278   //reopen for reading
00279   return make_input_pyramid_image(file);
00280 }
00281 
00282 vil_blocked_image_resource_sptr
00283 vil_tiff_file_format::make_blocked_output_image(vil_stream* vs,
00284                                                 unsigned nx,
00285                                                 unsigned ny,
00286                                                 unsigned nplanes,
00287                                                 unsigned size_block_i,
00288                                                 unsigned size_block_j,
00289                                                 enum vil_pixel_format format)
00290 {
00291   if (size_block_i%16!=0||size_block_j%16!=0)
00292   {
00293     vcl_cerr << "In vil_tiff_file_format - Block dimensions must be a multiple of 16\n";
00294     return 0;
00295   }
00296 
00297   tif_stream_structures* tss = new tif_stream_structures(vs);
00298   tss->filesize = 0;
00299   tss->tif = open_tiff(tss, "w");
00300   if (!tss->tif)
00301     return 0;
00302 
00303   //size_block_i==0 && size_block_j==0 specifies strips of one scanline
00304   //this constructor for h defines that the resource is to
00305   //be setup for writing
00306   vil_tiff_header* h = new vil_tiff_header(tss->tif, nx, ny, nplanes,
00307                                            format, size_block_i, size_block_j);
00308   if (!h->format_supported)
00309   {
00310     TIFFClose(tss->tif);
00311     delete h;
00312     return 0;
00313   }
00314   tif_smart_ptr tsptr = new tif_ref_cnt(tss->tif);
00315   return new vil_tiff_image(tsptr, h);
00316 }
00317 
00318 
00319 vil_image_resource_sptr
00320 vil_tiff_file_format::make_output_image(vil_stream* vs,
00321                                         unsigned ni,
00322                                         unsigned nj,
00323                                         unsigned nplanes,
00324                                         enum vil_pixel_format format)
00325 {
00326   return make_blocked_output_image(vs, ni, nj, nplanes, 0, 0, format).ptr();
00327 }
00328 
00329 vil_pyramid_image_resource_sptr
00330 vil_tiff_file_format::make_pyramid_output_image(char const* filename)
00331 {
00332   TIFF* out  = TIFFOpen(filename, "w");
00333   if (!out)
00334     return 0;
00335   bool open_for_reading = false;
00336   tif_smart_ptr tsptr = new tif_ref_cnt(out);
00337   return new vil_tiff_pyramid_resource(tsptr, open_for_reading);
00338 }
00339 
00340 char const* vil_tiff_file_format::tag() const
00341 {
00342   return vil_tiff_format_tag;
00343 }
00344 
00345 /////////////////////////////////////////////////////////////////////////////
00346 
00347 
00348 /////////////////////////////////////////////////////////////////////////////
00349 
00350 
00351 vil_tiff_image::vil_tiff_image(tif_smart_ptr const& tif_sptr,
00352                                vil_tiff_header* th, const unsigned nimages):
00353     t_(tif_sptr), h_(th), index_(0), nimages_(nimages)
00354 {
00355 }
00356 
00357 bool vil_tiff_image::get_property(char const * tag, void * value) const
00358 {
00359   if (vcl_strcmp(vil_property_quantisation_depth, tag)==0)
00360   {
00361     if (value)
00362       *static_cast<unsigned*>(value) = h_->bits_per_sample.val;
00363     return true;
00364   }
00365   if (vcl_strcmp(vil_property_size_block_i, tag)==0)
00366   {
00367     if (!h_->is_tiled())
00368       return false;
00369     if (value)
00370       *static_cast<unsigned*>(value) = this->size_block_i();
00371     return true;
00372   }
00373 
00374   if (vcl_strcmp(vil_property_size_block_j, tag)==0)
00375   {
00376     if (!h_->is_tiled())
00377       return false;
00378     if (value)
00379       *static_cast<unsigned*>(value) = this->size_block_j();
00380     return true;
00381   }
00382 
00383   return false;
00384 }
00385 #if HAS_GEOTIFF
00386 vil_geotiff_header* vil_tiff_image::get_geotiff_header()
00387 {
00388   vil_geotiff_header* gtif = new vil_geotiff_header(t_.tif());
00389   if (gtif->gtif_number_of_keys() == 0) {
00390     delete gtif;
00391     return 0;
00392   }
00393 
00394   return gtif;
00395 }
00396 #endif
00397 
00398 vil_pixel_format vil_tiff_image::pixel_format() const
00399 {
00400   return h_->pix_fmt;
00401 }
00402 
00403 vil_tiff_image::~vil_tiff_image()
00404 {
00405   delete h_;
00406 }
00407 
00408 //////
00409 //Lifted from nitf2.  Maybe generalize to support other file formats
00410 //////
00411 char const* vil_tiff_image::file_format() const
00412 {
00413   return vil_tiff_format_tag;
00414 }
00415 
00416 static void tif_swap16(vxl_byte *a, unsigned n)
00417 {
00418   for (unsigned i = 0; i < n * 2; i += 2)
00419     vcl_swap( a[i+0], a[i+1] );
00420 }
00421 
00422 static void tif_swap32(vxl_byte *a, unsigned n)
00423 {
00424   for (unsigned i = 0; i < n * 4; i += 4)
00425   {
00426     vcl_swap( a[i+0], a[i+3] );
00427     vcl_swap( a[i+1], a[i+2] );
00428   }
00429 }
00430 
00431 static void endian_swap( vxl_byte* a, unsigned n_bytes,
00432                          unsigned bytes_per_sample)
00433 {
00434   switch ( bytes_per_sample ) {
00435    case 1: break; // do nothing
00436    case 2: tif_swap16( a, n_bytes / 2 ); break; //16 bit
00437    case 4: tif_swap32( a, n_bytes / 4 ); break; //32 bit
00438    default: assert(!"Unsupported number of bytes per sample.");
00439   }
00440 }
00441 
00442 template<> bool* tiff_byte_align_data<bool>(bool* in_data, unsigned num_samples, unsigned in_bits_per_sample, bool* out_data)
00443 {
00444   switch (sizeof(bool))
00445   {
00446    case 1:
00447     tiff_byte_align_data((vxl_byte*)in_data, num_samples, in_bits_per_sample, (vxl_byte*)out_data);
00448     break;
00449    case 2:
00450     tiff_byte_align_data((vxl_uint_16*)in_data, num_samples, in_bits_per_sample, (vxl_uint_16*)out_data);
00451     break;
00452    case 4:
00453     tiff_byte_align_data((vxl_uint_32*)in_data, num_samples, in_bits_per_sample, (vxl_uint_32*)out_data);
00454     break;
00455    default:
00456     assert(!"Unsupported size of bool in tiff file format.");
00457   }
00458   return out_data;
00459 }
00460 
00461 // the sample is an integral data type
00462 bool integral_type(unsigned bits_per_sample)
00463 {
00464   switch (bits_per_sample)
00465   {
00466    case  8:
00467    case 16:
00468    case 32: return true;
00469    default: break;
00470   }
00471   return false;
00472 }
00473 
00474 template< class T >
00475 vil_memory_chunk_sptr
00476 tiff_maybe_byte_align_data(vil_memory_chunk_sptr in_data,
00477                            unsigned num_samples,
00478                            unsigned in_bits_per_sample,
00479                            unsigned bytes_per_block)
00480 {
00481   if (!integral_type(in_bits_per_sample))
00482   {
00483     vil_memory_chunk_sptr new_memory = new vil_memory_chunk(bytes_per_block, in_data->pixel_format());
00484 #ifdef DEBUG
00485     vcl_cout << "Debug tiff_byte_align_data:"
00486              << "  Num Samples = " << num_samples
00487              << "  Input Bits/Sample = " << in_bits_per_sample
00488              << "  Bytes/Block = " << bytes_per_block
00489              << "  Output Bytes/Sample = " << vil_pixel_format_sizeof_components(in_data->pixel_format())
00490              << vcl_flush;
00491 #endif
00492     T* out_ptr = reinterpret_cast<T*>(new_memory->data());
00493     T* in_ptr = reinterpret_cast<T*>(in_data->data());
00494     tiff_byte_align_data(in_ptr, num_samples, in_bits_per_sample, out_ptr );
00495 #ifdef DEBUG
00496     vcl_cout << " .\n" << vcl_flush;
00497 #endif
00498     return new_memory;
00499   }
00500   return in_data;
00501 }
00502 
00503 // don't do anything for float and double (bit shifting isn't allowed)
00504 template<> vil_memory_chunk_sptr tiff_maybe_byte_align_data<float>
00505            ( vil_memory_chunk_sptr in_data    ,
00506              unsigned /* num_samples */       ,
00507              unsigned /* in_bits_per_sample */,
00508              unsigned /* bytes per block */   )
00509 { return in_data; }
00510 
00511 template<> vil_memory_chunk_sptr tiff_maybe_byte_align_data<double>
00512            ( vil_memory_chunk_sptr in_data    ,
00513              unsigned /* num_samples */       ,
00514              unsigned /* in_bits_per_sample */,
00515              unsigned /* bytes per block */   )
00516 { return in_data; }
00517 
00518 ////////// End of lifted material //////
00519 
00520 // simple virtual methods on vil_image_resource
00521 unsigned vil_tiff_image::nplanes() const
00522 {
00523   return h_->nplanes;
00524 }
00525 
00526 unsigned vil_tiff_image::ni() const
00527 {
00528   if (h_->image_width.valid)
00529     return h_->image_width.val;
00530   return 0;
00531 }
00532 
00533 unsigned vil_tiff_image::nj() const
00534 {
00535   if (h_->image_length.valid)
00536     return h_->image_length.val;
00537   return 0;
00538 }
00539 
00540 //: block size in cols
00541 unsigned vil_tiff_image::size_block_i() const
00542 {
00543   if (h_->tile_width.valid)
00544     return static_cast<unsigned>(h_->tile_width.val);
00545   if (h_->image_width.valid)
00546     return static_cast<unsigned>(h_->image_width.val);
00547   return 0;
00548 }
00549 
00550 //: block size in rows.
00551 // For strips, the number of rows per strip can be larger
00552 // than the image length but data is only valid for the number of actual
00553 // image rows. For images with multiple strips, the last strip may be
00554 // cropped by the actual number of image rows.
00555 unsigned vil_tiff_image::size_block_j() const
00556 {
00557   if (h_->tile_length.valid)
00558     return static_cast<unsigned>(h_->tile_length.val);
00559 
00560   unsigned bps = static_cast<unsigned>(h_->bytes_per_strip());
00561   unsigned bpl = static_cast<unsigned>(h_->bytes_per_line());
00562   unsigned size = bps/bpl;
00563   return size;
00564   return 0;
00565 }
00566 
00567 //: Number of blocks in image width
00568 unsigned vil_tiff_image::n_block_i() const
00569 {
00570   if (h_->tile_width.valid)
00571     return static_cast<unsigned>(h_->tiles_across());
00572   return 1;
00573 }
00574 
00575 //: Number of blocks in image height
00576 unsigned vil_tiff_image::n_block_j() const
00577 {
00578   if (h_->tile_length.valid&&h_->image_length.valid)
00579     return static_cast<unsigned>(h_->tiles_down());
00580   return static_cast<unsigned>(h_->strips_per_image());
00581 }
00582 
00583 ///// end of simple virtual methods
00584 
00585 unsigned vil_tiff_image::
00586 block_index(unsigned block_i, unsigned block_j) const
00587 {
00588   return block_j*n_block_i() + block_i;
00589 }
00590 
00591 // the number of samples per block, irrespective of bit resolution
00592 unsigned vil_tiff_image::samples_per_block() const
00593 {
00594   if (h_->samples_per_pixel.valid)
00595     return static_cast<unsigned>(h_->samples_per_pixel.val*
00596                                  size_block_i()*size_block_j());
00597   return 0;
00598 }
00599 
00600 //: Transfer data from block to memory chunk, row by row
00601 // Since view and block are the same we can just blast across
00602 void vil_tiff_image::copy_byte_block(vxl_byte* data, const vxl_uint_32 nbytes, vil_memory_chunk_sptr& cnk) const
00603 {
00604   if (nbytes==0)
00605     return;
00606   vxl_byte* c_data = reinterpret_cast<vxl_byte*>(cnk->data());
00607   vcl_memcpy(c_data, data, nbytes);
00608 }
00609 
00610 //: map the input buffer into the view.
00611 // Note strips won't trigger byte
00612 // alignment, because they are already aligned at this point.
00613 vil_image_view_base_sptr vil_tiff_image::
00614 view_from_buffer(vil_pixel_format& fmt, vil_memory_chunk_sptr const& buf,
00615                  unsigned samples_per_block, unsigned bits_per_sample
00616                 ) const
00617 {
00618   vil_image_view_base_sptr view = 0;
00619   vil_memory_chunk_sptr  buf_out;
00620   unsigned spp = h_->samples_per_pixel.val;
00621   switch (fmt)
00622   {
00623 #define GET_BLOCK_CASE(FORMAT, T) \
00624    case FORMAT: { \
00625     vil_image_view_base_sptr view; \
00626     buf_out = tiff_maybe_byte_align_data<T>(buf, samples_per_block, \
00627                                             bits_per_sample, \
00628                                             samples_per_block*vil_pixel_format_sizeof_components(fmt)); \
00629     view = new vil_image_view<T>(buf_out, reinterpret_cast<T*>(buf_out->data()), \
00630                                  size_block_i(), size_block_j(), \
00631                                  spp, spp, size_block_i()*spp, 1); \
00632     return view; }
00633     GET_BLOCK_CASE(VIL_PIXEL_FORMAT_BYTE, vxl_byte);
00634     GET_BLOCK_CASE(VIL_PIXEL_FORMAT_SBYTE, vxl_sbyte);
00635 #if VXL_HAS_INT_64
00636     GET_BLOCK_CASE(VIL_PIXEL_FORMAT_UINT_64, vxl_uint_64);
00637     GET_BLOCK_CASE(VIL_PIXEL_FORMAT_INT_64, vxl_int_64);
00638 #endif
00639     GET_BLOCK_CASE(VIL_PIXEL_FORMAT_UINT_32, vxl_uint_32);
00640     GET_BLOCK_CASE(VIL_PIXEL_FORMAT_INT_32, vxl_int_32);
00641     GET_BLOCK_CASE(VIL_PIXEL_FORMAT_UINT_16, vxl_uint_16);
00642     GET_BLOCK_CASE(VIL_PIXEL_FORMAT_INT_16, vxl_int_16);
00643     GET_BLOCK_CASE(VIL_PIXEL_FORMAT_BOOL, bool);
00644     GET_BLOCK_CASE(VIL_PIXEL_FORMAT_FLOAT, float);
00645     GET_BLOCK_CASE(VIL_PIXEL_FORMAT_DOUBLE, double);
00646 #undef GET_BLOCK_CASE
00647    default:
00648     assert(!"Unknown vil data type in tiff file format");
00649     break;
00650   }
00651   return view;
00652 }
00653 
00654 // this internal block accessor is used for both tiled and
00655 // striped encodings
00656 vil_image_view_base_sptr
00657 vil_tiff_image::get_block( unsigned block_index_i,
00658                            unsigned block_index_j ) const
00659 {
00660   // the only two possibilities
00661   assert(h_->is_tiled() || h_->is_striped());
00662   //
00663   // If there are multiple images in the file it is
00664   // necessary to set the TIFF directory and file header corresponding to
00665   // this resource according to the index
00666   //
00667   if (nimages_>1)
00668   {
00669     if (TIFFSetDirectory(t_.tif(), index_)<=0)
00670       return 0;
00671     vil_tiff_header* h = new vil_tiff_header(t_.tif());
00672     //Cast away const
00673     vil_tiff_image* ti = (vil_tiff_image*)this;
00674     delete h_;
00675     ti->h_=h;
00676   }
00677 
00678   vil_image_view_base_sptr view = 0;
00679 
00680   //allocate input memory
00681   // input memory
00682   unsigned encoded_block_size = h_->encoded_bytes_per_block();
00683   assert(encoded_block_size>0);
00684   vxl_byte* data = new vxl_byte[encoded_block_size];
00685 
00686   //compute the block index
00687   unsigned blk_indx = this->block_index(block_index_i, block_index_j);
00688 
00689 
00690   vil_pixel_format fmt = vil_pixel_format_component_format(h_->pix_fmt);
00691 
00692   // input memory chunk
00693   vil_memory_chunk_sptr buf =
00694     new vil_memory_chunk(encoded_block_size, fmt);
00695   unsigned expanded_sample_bytes = vil_pixel_format_sizeof_components(fmt);
00696 
00697 
00698   if (h_->is_tiled())
00699   {
00700     if (TIFFReadEncodedTile(t_.tif(), blk_indx, data, (tsize_t) -1)<=0)
00701     {
00702       delete [] data;
00703       return view;
00704     }
00705     this->copy_byte_block(data, encoded_block_size, buf);
00706     delete [] data;
00707     if (h_->need_byte_swap())
00708       endian_swap( reinterpret_cast<vxl_byte*>(buf->data()),
00709                    encoded_block_size,
00710                    expanded_sample_bytes);
00711     return this->fill_block_from_tile(buf);
00712   }
00713 
00714   if (h_->is_striped())
00715   {
00716     if (TIFFReadEncodedStrip(t_.tif(), blk_indx, data, (tsize_t) -1)<=0)
00717     {
00718       delete [] data;
00719       return view;
00720     }
00721     this->copy_byte_block(data, encoded_block_size, buf);
00722     delete [] data;
00723     if (h_->need_byte_swap())
00724       endian_swap( reinterpret_cast<vxl_byte*>(buf->data()),
00725                    encoded_block_size,
00726                    expanded_sample_bytes);
00727     return this->fill_block_from_strip(buf);
00728   }
00729 
00730   return view;
00731 }
00732 
00733 //decode tiles: the tile is a contiguous raster scan of potentially
00734 //interleaved samples. This is an easy case since the tile is a
00735 //contiguous raster scan.
00736 vil_image_view_base_sptr vil_tiff_image::
00737 fill_block_from_tile(vil_memory_chunk_sptr const & buf) const
00738 {
00739   vil_image_view_base_sptr view = 0;
00740 
00741   //the size of the buffer when expanded to byte representation
00742   unsigned samples_per_block = this->samples_per_block();
00743   assert(samples_per_block>0);
00744 
00745   vil_pixel_format fmt = vil_pixel_format_component_format(h_->pix_fmt);
00746   view = view_from_buffer(fmt, buf, samples_per_block, h_->bits_per_sample.val);
00747   return view;
00748 }
00749 
00750 // decode strips.  The strip is somewhat different from the tile in that
00751 // it is organized around scan lines. If bits_per_pixel is not an integral
00752 // number of bytes then the last packed byte in the scan line will be only
00753 // partially filled. The header function, bytes_per_line() gives the actual
00754 // size of a scan line in the packed strip. The total size of the strip
00755 // in bytes is normally size_block_j()*bytes_per_line() but the last strip
00756 // may be truncated.
00757 vil_image_view_base_sptr vil_tiff_image::fill_block_from_strip(vil_memory_chunk_sptr const & buf) const
00758 {
00759   vil_image_view_base_sptr view = 0;
00760   vxl_uint_32 tl = size_block_j();
00761 
00762   unsigned bpl = h_->bytes_per_line();
00763   unsigned bytes_per_strip = h_->bytes_per_strip();
00764   unsigned lines_per_strip = bytes_per_strip/bpl;
00765 
00766   vil_pixel_format fmt = vil_pixel_format_component_format(h_->pix_fmt);
00767   unsigned expanded_bytes_per_sample =
00768     vil_pixel_format_sizeof_components(fmt);
00769   unsigned spl = h_->samples_per_line();
00770   unsigned bytes_expanded_line = spl*expanded_bytes_per_sample;
00771   //note here we make the last strip a full sized block to avoid
00772   //the messyness of multiple block sizes
00773   unsigned expanded_bytes_per_strip = tl*bytes_expanded_line;
00774 
00775   //pointer into the input packed strip buffer
00776   vxl_byte* buf_ptr = reinterpret_cast<vxl_byte*>(buf->data());
00777 
00778   //buffer for each scan line
00779   vil_memory_chunk_sptr line_buf =
00780     new vil_memory_chunk(bpl, fmt);
00781 
00782   //a buffer of zeros for filling partial strips to tile size
00783   vil_memory_chunk_sptr zero_buf =
00784     new vil_memory_chunk(bytes_expanded_line, fmt);
00785   vxl_byte* zero_ptr = reinterpret_cast<vxl_byte*>(zero_buf->data());
00786   for (unsigned i = 0; i<bytes_expanded_line; ++i)
00787     zero_ptr[i]=0;
00788 
00789   //buffer for the final unpacked output block
00790   vil_memory_chunk_sptr block_buf =
00791     new vil_memory_chunk(expanded_bytes_per_strip, fmt);
00792   vxl_byte* block_ptr = reinterpret_cast<vxl_byte*>(block_buf->data());
00793   //read scan lines from the strip and paste into the block
00794   for (unsigned j = 0; j<tl; ++j, buf_ptr+=bpl,
00795        block_ptr+=bytes_expanded_line)
00796   {
00797     if (j<lines_per_strip)
00798     {
00799       // get a row from the input buffer
00800       copy_byte_block(buf_ptr, bpl, line_buf);
00801       vil_memory_chunk_sptr out_line_buf;
00802       switch (fmt)
00803       {
00804 #define GET_LINE_CASE(FORMAT, T) \
00805        case FORMAT:\
00806         out_line_buf = \
00807           tiff_maybe_byte_align_data<T>(line_buf,\
00808                                         spl, h_->bits_per_sample.val,\
00809                                         bytes_expanded_line); \
00810         break
00811         GET_LINE_CASE(VIL_PIXEL_FORMAT_BYTE, vxl_byte);
00812         GET_LINE_CASE(VIL_PIXEL_FORMAT_SBYTE, vxl_sbyte);
00813 #if VXL_HAS_INT_64
00814         GET_LINE_CASE(VIL_PIXEL_FORMAT_UINT_64, vxl_uint_64);
00815         GET_LINE_CASE(VIL_PIXEL_FORMAT_INT_64, vxl_int_64);
00816 #endif
00817         GET_LINE_CASE(VIL_PIXEL_FORMAT_UINT_32, vxl_uint_32);
00818         GET_LINE_CASE(VIL_PIXEL_FORMAT_INT_32, vxl_int_32);
00819         GET_LINE_CASE(VIL_PIXEL_FORMAT_UINT_16, vxl_uint_16);
00820         GET_LINE_CASE(VIL_PIXEL_FORMAT_INT_16, vxl_int_16);
00821         GET_LINE_CASE(VIL_PIXEL_FORMAT_BOOL, bool);
00822         GET_LINE_CASE(VIL_PIXEL_FORMAT_FLOAT, float);
00823         GET_LINE_CASE(VIL_PIXEL_FORMAT_DOUBLE, double);
00824 #undef GET_LINE_CASE
00825        default:
00826         assert(!"Unknown vil data type in tiff file format");
00827         break;
00828       }
00829       //now we have the unpacked scan line in out_buf so copy to the view
00830       //buffer.
00831       vxl_byte* out_line_buf_ptr =
00832         reinterpret_cast<vxl_byte*>(out_line_buf->data());
00833       vcl_memcpy(block_ptr, out_line_buf_ptr, bytes_expanded_line);
00834     }
00835     else
00836       vcl_memcpy(block_ptr, zero_ptr, bytes_expanded_line);
00837   }
00838 
00839   return this->view_from_buffer(fmt, block_buf, spl*tl,
00840                                 expanded_bytes_per_sample*8);
00841 }
00842 
00843 void vil_tiff_image::pad_block_with_zeros(unsigned ioff, unsigned joff,
00844                                           unsigned iclip, unsigned jclip,
00845                                           unsigned bytes_per_pixel,
00846                                           vxl_byte* block_buf)
00847 {
00848   unsigned jstep = size_block_i()*bytes_per_pixel;
00849   unsigned row_start = ioff*bytes_per_pixel;
00850   unsigned bptr = 0;
00851   //fill leading part with zeroes
00852   if (ioff>0||joff>0)
00853     for (unsigned j = 0; j<joff-1; ++j)
00854     {
00855       unsigned row_ptr = row_start;
00856       for (unsigned i = 0; i<ioff-1; ++i)
00857       {
00858         for (unsigned p = 0; p<nplanes(); ++p)
00859           *(block_buf + bptr + row_ptr + p) = 0;
00860         row_ptr += bytes_per_pixel;
00861       }
00862       bptr += jstep;
00863     }
00864   bptr = jstep*jclip;
00865   row_start = iclip*bytes_per_pixel;
00866   if (iclip>0||jclip>0)
00867     for (unsigned j = jclip; j<size_block_j(); ++j)
00868     {
00869       unsigned row_ptr = row_start;
00870       for (unsigned i = iclip; i<size_block_i(); ++i)
00871       {
00872         for (unsigned p = 0; p<nplanes(); ++p)
00873           *(block_buf + bptr + row_ptr + p) = 0;
00874         row_ptr += bytes_per_pixel;
00875       }
00876       bptr += jstep;
00877     }
00878 }
00879 
00880 void vil_tiff_image::fill_block_from_view(unsigned bi, unsigned bj,
00881                                           unsigned i0, unsigned j0,
00882                                           unsigned ioff, unsigned joff,
00883                                           unsigned iclip, unsigned jclip,
00884                                           const vil_image_view_base& im,
00885                                           vxl_byte*& block_buf)
00886 {
00887   unsigned bytes_per_sample = h_->bytes_per_sample();
00888   unsigned bytes_per_pixel = bytes_per_sample*nplanes();
00889   unsigned sbi = size_block_i(), sbj = size_block_j();
00890   unsigned bytes_per_block=bytes_per_pixel*sbi*sbj;
00891   unsigned view_i0 = bi*sbi-i0, view_j0 = bj*sbj-j0;
00892   unsigned block_jstep = sbi*bytes_per_pixel;
00893 #if 0
00894   //Causes warnings. Leave here to document default values
00895   unsigned view_istep = 1, view_jstep = im.ni()*bytes_per_pixel, view_pstep = 1;
00896 #endif
00897   vcl_ptrdiff_t view_istep, view_jstep, view_pstep;
00898   vxl_byte* view_buf;
00899   //Cast the pixel type and reinterpret upper_left_ptr as a byte array.
00900   switch (h_->pix_fmt)
00901   {
00902 #define GET_VIEW_PTR(FORMAT, T) \
00903    case FORMAT: { \
00904     vil_image_view<T> view = static_cast<const vil_image_view<T>& >(im);\
00905     view_istep = view.istep(); view_jstep = view.jstep(); view_pstep = view.planestep(); \
00906     view_buf = reinterpret_cast<vxl_byte*>(view.top_left_ptr());\
00907    } break
00908     GET_VIEW_PTR(VIL_PIXEL_FORMAT_BYTE, vxl_byte);
00909     GET_VIEW_PTR(VIL_PIXEL_FORMAT_SBYTE, vxl_sbyte);
00910 #if VXL_HAS_INT_64
00911     GET_VIEW_PTR(VIL_PIXEL_FORMAT_UINT_64, vxl_uint_64);
00912     GET_VIEW_PTR(VIL_PIXEL_FORMAT_INT_64, vxl_int_64);
00913 #endif
00914     GET_VIEW_PTR(VIL_PIXEL_FORMAT_UINT_32, vxl_uint_32);
00915     GET_VIEW_PTR(VIL_PIXEL_FORMAT_INT_32, vxl_int_32);
00916     GET_VIEW_PTR(VIL_PIXEL_FORMAT_UINT_16, vxl_uint_16);
00917     GET_VIEW_PTR(VIL_PIXEL_FORMAT_INT_16, vxl_int_16);
00918     GET_VIEW_PTR(VIL_PIXEL_FORMAT_BOOL, bool);
00919     GET_VIEW_PTR(VIL_PIXEL_FORMAT_FLOAT, float);
00920     GET_VIEW_PTR(VIL_PIXEL_FORMAT_DOUBLE, double);
00921 #undef GET_VIEW_PTR
00922    default:
00923     assert(!"Unknown vil data type.");
00924     return;
00925   }
00926   //initial index into block buffer
00927   unsigned bptr = joff*block_jstep;
00928   unsigned ibstart = ioff*bytes_per_pixel;
00929   vcl_ptrdiff_t vistp = view_istep*bytes_per_sample;
00930   vcl_ptrdiff_t vjstp = view_jstep*bytes_per_sample;
00931   vcl_ptrdiff_t vpstp = view_pstep*bytes_per_sample;
00932   //initial index into view buffer
00933   // note that it is necessary to add the offset to the start of the
00934   // current block within the view, (view_i0, view_j0)
00935   vcl_ptrdiff_t vptr = (view_j0 + joff)*vjstp;
00936   unsigned ivstart = (view_i0 + ioff)*bytes_per_pixel;
00937   for (unsigned j = joff; j<jclip; ++j)
00938   {
00939     vcl_ptrdiff_t vrow_ptr = ivstart;
00940     vcl_ptrdiff_t brow_ptr = ibstart;
00941     for (unsigned i = ioff; i<iclip; ++i)
00942     {
00943       vcl_ptrdiff_t bpptr = 0, vpptr = 0;
00944       for (unsigned p = 0; p<nplanes(); ++p)
00945       {
00946         for (unsigned b = 0; b<bytes_per_sample; ++b)
00947           *(block_buf + bptr + brow_ptr + bpptr + b) =
00948             *(view_buf + vptr + vrow_ptr + vpptr + b);
00949         bpptr += bytes_per_sample; vpptr += vpstp;
00950       }
00951       brow_ptr += bytes_per_pixel; vrow_ptr += vistp;
00952     }
00953     bptr += block_jstep; vptr += vjstp;
00954   }
00955 
00956   //handle the case of bool  (other packed formats not supported for writing)
00957   if (this->pixel_format() == VIL_PIXEL_FORMAT_BOOL)
00958   {
00959     unsigned outsize = (bytes_per_block+7*sizeof(bool))/(8*sizeof(bool));
00960     vxl_byte* outbuf = new vxl_byte[outsize];
00961     this->bitpack_block(bytes_per_block, block_buf, outbuf);
00962     delete [] block_buf;
00963     block_buf = outbuf; // bytes_per_block=outsize;
00964   }
00965 }
00966 
00967 bool vil_tiff_image::write_block_to_file(unsigned bi, unsigned bj,
00968                                          unsigned block_size_bytes,
00969                                          vxl_byte* block_buf)
00970 {
00971   unsigned blk_indx = this->block_index(bi, bj);
00972   if (h_->is_tiled())
00973     return TIFFWriteEncodedTile(t_.tif(), blk_indx, block_buf,
00974                                 block_size_bytes)>0;
00975   if (h_->is_striped())
00976     return TIFFWriteEncodedStrip(t_.tif(), blk_indx, block_buf,
00977                                  block_size_bytes ) > 0;
00978   return false;
00979 }
00980 
00981 // Just support packing of bool data for now
00982 // ultimately we need the opposite of maybe_byte_align_data
00983 void vil_tiff_image::bitpack_block(unsigned bytes_per_block,
00984                                    vxl_byte* in_block_buf,
00985                                    vxl_byte* out_block_buf)
00986 {
00987   unsigned bytes_per_bool = sizeof(bool);
00988   vxl_byte* bl = new vxl_byte[bytes_per_bool];
00989   unsigned bitctr = 0;
00990   unsigned outctr = 0;
00991   vxl_byte packed_byte=0;
00992   for (unsigned i = 0; i<bytes_per_block; )
00993   {
00994     //test for a completed packed byte
00995     if (bitctr==8)
00996     {
00997       bitctr = 0;
00998       out_block_buf[outctr] = packed_byte;
00999       packed_byte = 0;
01000       ++outctr;
01001     }
01002     //pack a bool into the next bit
01003     for (unsigned b = 0; b<bytes_per_bool; ++b)
01004       bl[b] = *(in_block_buf + i + b);
01005     bool blv = *(reinterpret_cast<bool*>(bl));
01006     if (blv)
01007       packed_byte |= vxl_byte(1<<(7-bitctr)); //set a "1"
01008     else
01009       packed_byte &= vxl_byte(~(1<<(7-bitctr)));//set a "0"
01010     ++bitctr;
01011 
01012     i+=bytes_per_bool;
01013     if (i>=bytes_per_block) //output last (partial) byte
01014       out_block_buf[outctr] = packed_byte;
01015   }
01016   delete [] bl;
01017 }
01018 
01019 //an internal form of put_block for convenience
01020 //write the indicated block to file, padding with zeros if necessary
01021 //image view im is an arbitrary region of image that has to be decomposed into
01022 //blocks. The resource is written with zeros if the input view doesn't
01023 //correspond to exact block boundaries.  Subsequent put_view calls could
01024 //fill in the missing image data.
01025 bool vil_tiff_image::put_block(unsigned bi, unsigned bj, unsigned i0,
01026                                unsigned j0, const vil_image_view_base& im)
01027 {
01028   //Get the block offset and clipping parameters
01029 
01030   //ioff and joff are the offsets within a block to the start of valid data
01031   unsigned ioff =0, joff = 0;
01032   unsigned sbi = size_block_i(), sbj = size_block_j();
01033   unsigned iclip =sbi , jclip = sbj;
01034   //column offset into block. fill [0->ioff-1]
01035   if (bi*sbi<i0&&(bi+1)*sbi>i0)
01036     if (!block_i_offset(bi, i0, ioff))
01037       return false;
01038   //row offset into block fill [0->joff-1]
01039   if (bj*sbj<j0&&(bj+1)*sbj>j0)
01040     if (!block_j_offset(bj, j0, joff))
01041       return false;
01042 
01043   //iclip and jclip are the start of invalid data at the right and
01044   //bottom of partially filled blocks
01045 
01046   //right block margin to be padded [iclip -> size_block_i()-1]
01047   if ( (bi+1)*sbi > (im.ni()+i0) )
01048   {
01049     iclip = (i0+im.ni())-bi*sbi;
01050     if (iclip > sbi)
01051       return false;
01052   }
01053 
01054   //bottom block margin to be padded [jclip -> size_block_j()-1]
01055   if ( (bj+1)*sbj > (im.nj()+j0) )
01056   {
01057     jclip = (j0+im.nj())-bj*sbj;
01058     if (jclip > sbj)
01059       return false;
01060   }
01061   unsigned bps = h_->bytes_per_sample();
01062   unsigned bytes_per_pixel = bps*nplanes();
01063 
01064   unsigned bytes_per_block = bytes_per_pixel*sbi*sbj;
01065 
01066 
01067   //the data buffer for the block
01068   vxl_byte* block_buf = new vxl_byte[bytes_per_block];
01069 
01070   this->pad_block_with_zeros(ioff, joff, iclip, jclip,
01071                              bytes_per_pixel, block_buf);
01072 
01073 
01074   this->fill_block_from_view(bi, bj, i0, j0, ioff, joff, iclip, jclip,
01075                              im, block_buf);
01076   //write the block to the tiff file
01077   bool good_write = write_block_to_file(bi, bj, bytes_per_block, block_buf);
01078   delete [] block_buf;
01079   return good_write;
01080 }
01081 
01082 bool vil_tiff_image::put_view(const vil_image_view_base& im,
01083                               unsigned i0, unsigned j0)
01084 {
01085   if (!vil_image_resource::view_fits(im, i0, j0))
01086   {
01087     vil_exception_warning(vil_exception_out_of_bounds("vil_tiff_image::put_view"));
01088     return false;
01089   }
01090 
01091   unsigned tw = size_block_i(), tl = size_block_j();
01092   if (tw==0||tl==0)
01093     return false;
01094   unsigned  bi_start = i0/tw, bi_end = (i0+im.ni()-1)/tw;
01095   unsigned  bj_start = j0/tl, bj_end = (j0+im.nj()-1)/tl;
01096   for (unsigned bi = bi_start; bi<=bi_end; ++bi)
01097     for (unsigned bj = bj_start; bj<=bj_end; ++bj)
01098       if (!this->put_block(bi, bj, i0, j0, im))
01099         return false;
01100   return true;
01101 }
01102 
01103 // The virtual put_block method. In this case the view is a complete block
01104 bool vil_tiff_image::put_block( unsigned  block_index_i,
01105                                 unsigned  block_index_j,
01106                                 const vil_image_view_base& blk )
01107 {
01108   if (blk.ni()==0||blk.nj()==0)
01109     return false;
01110   unsigned sbi = this->size_block_i(), sbj = this->size_block_j();
01111   unsigned bps = h_->bytes_per_sample();
01112   unsigned bytes_per_pixel = bps*nplanes();
01113 
01114   unsigned bytes_per_block = bytes_per_pixel*sbi*sbj;
01115 
01116   //the data buffer for the block
01117   vxl_byte* block_buf = new vxl_byte[bytes_per_block];
01118 
01119   this->fill_block_from_view(0, 0, 0, 0, 0, 0,sbi, sbj, blk, block_buf);
01120 
01121   //write the block to the tiff file
01122   bool good_write = write_block_to_file(block_index_i, block_index_j, bytes_per_block, block_buf);
01123   delete [] block_buf;
01124   return good_write;
01125 }
01126 
01127 //Begin pyramid resource
01128 static bool level_compare(tiff_pyramid_level* const l1, tiff_pyramid_level* const l2)
01129 {
01130   assert(l1&&l2);
01131   return l1->ni_ > l2->ni_;
01132 }
01133 
01134 //: Assumes that the image in level 0 is the largest
01135 void vil_tiff_pyramid_resource::normalize_scales()
01136 {
01137   unsigned nlevels = this->nlevels();
01138   if (nlevels==0)
01139     return;
01140   levels_[0]->scale_ = 1.0f;
01141   if (nlevels==1)
01142     return;
01143   float ni0 = static_cast<float>(levels_[0]->ni_);
01144   for (unsigned i = 1; i<nlevels; ++i)
01145     levels_[i]->scale_ = static_cast<float>(levels_[i]->ni_)/ni0;
01146 }
01147 
01148 //:find the level closest to the specified scale
01149 tiff_pyramid_level* vil_tiff_pyramid_resource::closest(const float scale) const
01150 {
01151   unsigned nlevels = this->nlevels();
01152   if (nlevels == 0)
01153     return 0;
01154   if (nlevels == 1)
01155     return levels_[0];
01156   float mind = 1.0e08f;//huge scale;
01157   unsigned lmin = 0;
01158   for (unsigned i = 0; i<nlevels; ++i)
01159   {
01160     float ds = vcl_fabs(scale - levels_[i]->scale_);
01161     if (ds<mind)
01162     {
01163       mind = ds;
01164       lmin = i;
01165     }
01166   }
01167   tiff_pyramid_level* pl = levels_[lmin];
01168   if (pl)
01169     pl->cur_level_ = lmin;
01170   return pl;
01171 }
01172 
01173 vil_tiff_pyramid_resource::vil_tiff_pyramid_resource()
01174   : read_(true), t_(0)
01175 {
01176 }
01177 
01178 vil_tiff_pyramid_resource::
01179 vil_tiff_pyramid_resource(tif_smart_ptr const& t, bool read)
01180   : read_(read), t_(t)
01181 {
01182   bool trace = false;
01183   if (!read)
01184     return;
01185   //for reading we need to set up the levels
01186   while (true)
01187   {
01188     vil_tiff_header h(t_.tif());
01189     if (trace)
01190       vcl_cerr << "In vil_tiff_pyramid_resource constructor"
01191                << " constructed header\n"
01192                << "n-levels = " << this->nlevels() << '\n';
01193     tiff_pyramid_level* pl = new tiff_pyramid_level(this->nlevels(),
01194                                                     h.image_width.val,
01195                                                     h.image_length.val,
01196                                                     h.nplanes,
01197                                                     h.pix_fmt);
01198     levels_.push_back(pl);
01199     if (trace)
01200       vcl_cerr << "In vil_tiff_pyramid_resource constructor"
01201                << " constructed level\n";
01202     int status = TIFFReadDirectory(t_.tif());
01203     if (trace)
01204       vcl_cerr << "In vil_tiff_pyramid_resource constructor"
01205                << " Read new directory\n";
01206 
01207     if (!status)
01208       break;
01209   }
01210   if (trace)
01211     vcl_cerr << "In vil_tiff_pyramid_resource constructor"
01212              << " Begin sorting\n";
01213   //sort the pyramid
01214   vcl_sort(levels_.begin(), levels_.end(), level_compare);
01215   //normalize the scales
01216   this->normalize_scales();
01217 }
01218 
01219 vil_tiff_pyramid_resource::~vil_tiff_pyramid_resource()
01220 {
01221   for (unsigned L = 0; L<this->nlevels(); ++L)
01222     delete levels_[L];
01223 }
01224 
01225 //:Get a partial view from the image from a specified pyramid level
01226 vil_image_view_base_sptr
01227 vil_tiff_pyramid_resource::get_copy_view(unsigned i0, unsigned n_i,
01228                                          unsigned j0, unsigned n_j,
01229                                          unsigned level) const
01230 {
01231   unsigned nl = this->nlevels();
01232   if (level>=nl)
01233     return vil_image_view_base_sptr();
01234   vil_image_resource_sptr resc = this->get_resource(level);
01235   //scale input coordinates to the scale of the level
01236   float scale = levels_[level]->scale_;
01237   float fi0 = vcl_floor(scale*i0), fj0 = vcl_floor(scale*j0);
01238   float fni = vcl_floor(scale*n_i), fnj = vcl_floor(scale*n_j);
01239   unsigned si0 = static_cast<unsigned>(fi0);
01240   unsigned sj0 = static_cast<unsigned>(fj0);
01241   unsigned sni = static_cast<unsigned>(fni);
01242   if (sni == 0) sni = 1;//can't have less than one pixel
01243   unsigned snj = static_cast<unsigned>(fnj);
01244   if (snj == 0) snj = 1;//can't have less than one pixel
01245   vil_image_view_base_sptr view = resc->get_copy_view(si0, sni, sj0, snj);
01246 #if 0 //DON'T NEED CLEAR?
01247   resc->clear_TIFF();
01248 #endif
01249   return view;
01250 }
01251 
01252 //:Get a partial view from the image in the pyramid closest to scale.
01253 // The origin and size parameters are in the coordinate system
01254 // of the base image. The scale factor is with respect to the base
01255 // image (base scale = 1.0).
01256 vil_image_view_base_sptr
01257 vil_tiff_pyramid_resource::get_copy_view(unsigned i0, unsigned n_i,
01258                                          unsigned j0, unsigned n_j,
01259                                          const float scale,
01260                                          float& actual_scale) const
01261 {
01262   // Get the closest scale
01263   tiff_pyramid_level* pl  = this->closest(scale);
01264   if (!pl)
01265     return 0;
01266   actual_scale = pl->scale_;
01267   return this->get_copy_view(i0, n_i, j0, n_j, pl->cur_level_);
01268 }
01269 
01270 //: Put the data in this view back into the image source at specified level.
01271 // Only can be written once.
01272 bool vil_tiff_pyramid_resource::put_resource(vil_image_resource_sptr const& ir)
01273 {
01274   unsigned level = this->nlevels();
01275   unsigned ni = ir->ni(), nj = ir->nj();
01276   unsigned nplanes = ir->nplanes();
01277   vil_pixel_format fmt = ir->pixel_format();
01278   vil_blocked_image_resource_sptr bir = blocked_image_resource(ir);
01279   unsigned sbi = 0, sbj = 0;
01280   if (bir) { sbi = bir->size_block_i(); sbj = bir->size_block_j(); }
01281   // setup the image header for the level
01282   vil_tiff_header* h = new vil_tiff_header(t_.tif(), ni, nj, nplanes,
01283                                            fmt, sbi, sbj);
01284 
01285   /* We are writing single page of the multipage file */
01286   TIFFSetField(t_.tif(), TIFFTAG_SUBFILETYPE, FILETYPE_PAGE);
01287   /* Set the page number */
01288   TIFFSetField(t_.tif(), TIFFTAG_PAGENUMBER,level, 3);
01289   vil_tiff_image* ti = new vil_tiff_image(t_, h, level);
01290   vil_image_resource_sptr resc = ti;
01291   if (!vil_copy_deep(ir, resc))
01292     return false;
01293 #if 0 //DON'T NEED CLEAR?
01294   ti->clear_TIFF();
01295 #endif
01296   tiff_pyramid_level* pl = new tiff_pyramid_level((unsigned int)(levels_.size()), ni, nj, nplanes, fmt);
01297   levels_.push_back(pl);
01298   int status = TIFFWriteDirectory(t_.tif());
01299   return status == 1 ;
01300 }
01301 //: returns the pyramid resource at the specified level
01302 vil_image_resource_sptr vil_tiff_pyramid_resource::get_resource(const unsigned level) const
01303 {
01304   unsigned nl = this->nlevels();
01305   if (level>=nl)
01306     return 0;
01307   // setup the image header for the level
01308   unsigned header_index = levels_[level]->header_index_;
01309   // The status value should be checked here
01310   if (TIFFSetDirectory(t_.tif(), header_index)<=0)
01311     return 0;
01312   vil_tiff_header* h = new vil_tiff_header(t_.tif());
01313   vil_tiff_image* i = new vil_tiff_image(t_, h, nl);
01314   i->set_index(header_index);
01315   return i;
01316 }