Main Page | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Class Members | File Members | Related Pages

vil_tiff.cxx

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