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 tss;
00312     delete h;
00313     return 0;
00314   }
00315   tif_smart_ptr tsptr = new tif_ref_cnt(tss->tif);
00316   return new vil_tiff_image(tsptr, h);
00317 }
00318 
00319 
00320 vil_image_resource_sptr
00321 vil_tiff_file_format::make_output_image(vil_stream* vs,
00322                                         unsigned ni,
00323                                         unsigned nj,
00324                                         unsigned nplanes,
00325                                         enum vil_pixel_format format)
00326 {
00327   return make_blocked_output_image(vs, ni, nj, nplanes, 0, 0, format).ptr();
00328 }
00329 
00330 vil_pyramid_image_resource_sptr
00331 vil_tiff_file_format::make_pyramid_output_image(char const* filename)
00332 {
00333   TIFF* out  = TIFFOpen(filename, "w");
00334   if (!out)
00335     return 0;
00336   bool open_for_reading = false;
00337   tif_smart_ptr tsptr = new tif_ref_cnt(out);
00338   return new vil_tiff_pyramid_resource(tsptr, open_for_reading);
00339 }
00340 
00341 char const* vil_tiff_file_format::tag() const
00342 {
00343   return vil_tiff_format_tag;
00344 }
00345 
00346 /////////////////////////////////////////////////////////////////////////////
00347 
00348 
00349 /////////////////////////////////////////////////////////////////////////////
00350 
00351 
00352 vil_tiff_image::vil_tiff_image(tif_smart_ptr const& tif_sptr,
00353                                vil_tiff_header* th, const unsigned nimages):
00354     t_(tif_sptr), h_(th), index_(0), nimages_(nimages)
00355 {
00356 }
00357 
00358 bool vil_tiff_image::get_property(char const * tag, void * value) const
00359 {
00360   if (vcl_strcmp(vil_property_quantisation_depth, tag)==0)
00361   {
00362     if (value)
00363       *static_cast<unsigned*>(value) = h_->bits_per_sample.val;
00364     return true;
00365   }
00366   if (vcl_strcmp(vil_property_size_block_i, tag)==0)
00367   {
00368     if (!h_->is_tiled())
00369       return false;
00370     if (value)
00371       *static_cast<unsigned*>(value) = this->size_block_i();
00372     return true;
00373   }
00374 
00375   if (vcl_strcmp(vil_property_size_block_j, tag)==0)
00376   {
00377     if (!h_->is_tiled())
00378       return false;
00379     if (value)
00380       *static_cast<unsigned*>(value) = this->size_block_j();
00381     return true;
00382   }
00383 
00384   return false;
00385 }
00386 #if HAS_GEOTIFF
00387 vil_geotiff_header* vil_tiff_image::get_geotiff_header()
00388 {
00389   vil_geotiff_header* gtif = new vil_geotiff_header(t_.tif());
00390   if (gtif->gtif_number_of_keys() == 0) {
00391     delete gtif;
00392     return 0;
00393   }
00394 
00395   return gtif;
00396 }
00397 #endif
00398 
00399 vil_pixel_format vil_tiff_image::pixel_format() const
00400 {
00401   return h_->pix_fmt;
00402 }
00403 
00404 vil_tiff_image::~vil_tiff_image()
00405 {
00406   delete h_;
00407 }
00408 
00409 //////
00410 //Lifted from nitf2.  Maybe generalize to support other file formats
00411 //////
00412 char const* vil_tiff_image::file_format() const
00413 {
00414   return vil_tiff_format_tag;
00415 }
00416 
00417 static void tif_swap16(vxl_byte *a, unsigned n)
00418 {
00419   for (unsigned i = 0; i < n * 2; i += 2)
00420     vcl_swap( a[i+0], a[i+1] );
00421 }
00422 
00423 static void tif_swap32(vxl_byte *a, unsigned n)
00424 {
00425   for (unsigned i = 0; i < n * 4; i += 4)
00426   {
00427     vcl_swap( a[i+0], a[i+3] );
00428     vcl_swap( a[i+1], a[i+2] );
00429   }
00430 }
00431 
00432 static void endian_swap( vxl_byte* a, unsigned n_bytes,
00433                          unsigned bytes_per_sample)
00434 {
00435   switch ( bytes_per_sample ) {
00436    case 1: break; // do nothing
00437    case 2: tif_swap16( a, n_bytes / 2 ); break; //16 bit
00438    case 4: tif_swap32( a, n_bytes / 4 ); break; //32 bit
00439    default: assert(!"Unsupported number of bytes per sample.");
00440   }
00441 }
00442 
00443 template<> bool* tiff_byte_align_data<bool>(bool* in_data, unsigned num_samples, unsigned in_bits_per_sample, bool* out_data)
00444 {
00445   switch (sizeof(bool))
00446   {
00447    case 1:
00448     tiff_byte_align_data((vxl_byte*)in_data, num_samples, in_bits_per_sample, (vxl_byte*)out_data);
00449     break;
00450    case 2:
00451     tiff_byte_align_data((vxl_uint_16*)in_data, num_samples, in_bits_per_sample, (vxl_uint_16*)out_data);
00452     break;
00453    case 4:
00454     tiff_byte_align_data((vxl_uint_32*)in_data, num_samples, in_bits_per_sample, (vxl_uint_32*)out_data);
00455     break;
00456    default:
00457     assert(!"Unsupported size of bool in tiff file format.");
00458   }
00459   return out_data;
00460 }
00461 
00462 // the sample is an integral data type
00463 bool integral_type(unsigned bits_per_sample)
00464 {
00465   switch (bits_per_sample)
00466   {
00467    case  8:
00468    case 16:
00469    case 32: return true;
00470    default: break;
00471   }
00472   return false;
00473 }
00474 
00475 template< class T >
00476 vil_memory_chunk_sptr
00477 tiff_maybe_byte_align_data(vil_memory_chunk_sptr in_data,
00478                            unsigned num_samples,
00479                            unsigned in_bits_per_sample,
00480                            unsigned bytes_per_block)
00481 {
00482   if (!integral_type(in_bits_per_sample))
00483   {
00484     vil_memory_chunk_sptr new_memory = new vil_memory_chunk(bytes_per_block, in_data->pixel_format());
00485 #ifdef DEBUG
00486     vcl_cout << "Debug tiff_byte_align_data:"
00487              << "  Num Samples = " << num_samples
00488              << "  Input Bits/Sample = " << in_bits_per_sample
00489              << "  Bytes/Block = " << bytes_per_block
00490              << "  Output Bytes/Sample = " << vil_pixel_format_sizeof_components(in_data->pixel_format())
00491              << vcl_flush;
00492 #endif
00493     T* out_ptr = reinterpret_cast<T*>(new_memory->data());
00494     T* in_ptr = reinterpret_cast<T*>(in_data->data());
00495     tiff_byte_align_data(in_ptr, num_samples, in_bits_per_sample, out_ptr );
00496 #ifdef DEBUG
00497     vcl_cout << " .\n" << vcl_flush;
00498 #endif
00499     return new_memory;
00500   }
00501   return in_data;
00502 }
00503 
00504 // don't do anything for float and double (bit shifting isn't allowed)
00505 template<> vil_memory_chunk_sptr tiff_maybe_byte_align_data<float>
00506            ( vil_memory_chunk_sptr in_data    ,
00507              unsigned /* num_samples */       ,
00508              unsigned /* in_bits_per_sample */,
00509              unsigned /* bytes per block */   )
00510 { return in_data; }
00511 
00512 template<> vil_memory_chunk_sptr tiff_maybe_byte_align_data<double>
00513            ( vil_memory_chunk_sptr in_data    ,
00514              unsigned /* num_samples */       ,
00515              unsigned /* in_bits_per_sample */,
00516              unsigned /* bytes per block */   )
00517 { return in_data; }
00518 
00519 ////////// End of lifted material //////
00520 
00521 // simple virtual methods on vil_image_resource
00522 unsigned vil_tiff_image::nplanes() const
00523 {
00524   return h_->nplanes;
00525 }
00526 
00527 unsigned vil_tiff_image::ni() const
00528 {
00529   if (h_->image_width.valid)
00530     return h_->image_width.val;
00531   return 0;
00532 }
00533 
00534 unsigned vil_tiff_image::nj() const
00535 {
00536   if (h_->image_length.valid)
00537     return h_->image_length.val;
00538   return 0;
00539 }
00540 
00541 //block size in cols
00542 unsigned vil_tiff_image::size_block_i() const
00543 {
00544   if (h_->tile_width.valid)
00545     return static_cast<unsigned>(h_->tile_width.val);
00546   if (h_->image_width.valid)
00547     return static_cast<unsigned>(h_->image_width.val);
00548   return 0;
00549 }
00550 
00551 //block size in rows. 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 //croped by the acutal 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.  Note strips won't trigger byte
00611 //alignment, because they are already aligned at this point.
00612 vil_image_view_base_sptr vil_tiff_image::
00613 view_from_buffer(vil_pixel_format& fmt, vil_memory_chunk_sptr const& buf,
00614                  unsigned samples_per_block, unsigned bits_per_sample
00615                 ) const
00616 {
00617   vil_image_view_base_sptr view = 0;
00618   vil_memory_chunk_sptr  buf_out;
00619   unsigned spp = h_->samples_per_pixel.val;
00620   switch (fmt)
00621   {
00622 #define GET_BLOCK_CASE(FORMAT, T) \
00623    case FORMAT: { \
00624     vil_image_view_base_sptr view; \
00625     buf_out = tiff_maybe_byte_align_data<T>(buf, samples_per_block, \
00626                                             bits_per_sample, \
00627                                             samples_per_block*vil_pixel_format_sizeof_components(fmt)); \
00628     view = new vil_image_view<T>(buf_out, reinterpret_cast<T*>(buf_out->data()), \
00629                                  size_block_i(), size_block_j(), \
00630                                  spp, spp, size_block_i()*spp, 1); \
00631     return view; }
00632     GET_BLOCK_CASE(VIL_PIXEL_FORMAT_BYTE, vxl_byte);
00633     GET_BLOCK_CASE(VIL_PIXEL_FORMAT_SBYTE, vxl_sbyte);
00634 #if VXL_HAS_INT_64
00635     GET_BLOCK_CASE(VIL_PIXEL_FORMAT_UINT_64, vxl_uint_64);
00636     GET_BLOCK_CASE(VIL_PIXEL_FORMAT_INT_64, vxl_int_64);
00637 #endif
00638     GET_BLOCK_CASE(VIL_PIXEL_FORMAT_UINT_32, vxl_uint_32);
00639     GET_BLOCK_CASE(VIL_PIXEL_FORMAT_INT_32, vxl_int_32);
00640     GET_BLOCK_CASE(VIL_PIXEL_FORMAT_UINT_16, vxl_uint_16);
00641     GET_BLOCK_CASE(VIL_PIXEL_FORMAT_INT_16, vxl_int_16);
00642     GET_BLOCK_CASE(VIL_PIXEL_FORMAT_BOOL, bool);
00643     GET_BLOCK_CASE(VIL_PIXEL_FORMAT_FLOAT, float);
00644     GET_BLOCK_CASE(VIL_PIXEL_FORMAT_DOUBLE, double);
00645 #undef GET_BLOCK_CASE
00646    default:
00647     assert(!"Unknown vil data type in tiff file format");
00648     break;
00649   }
00650   return view;
00651 }
00652 
00653 // this internal block accessor is used for both tiled and
00654 // striped encodings
00655 vil_image_view_base_sptr
00656 vil_tiff_image::get_block( unsigned block_index_i,
00657                            unsigned block_index_j ) const
00658 {
00659   //the only two possibilities
00660   assert(h_->is_tiled()||h_->is_striped());
00661   //
00662   //If there are multiple images in the file it is
00663   //necessary to set the TIFF directory and file header corresponding to
00664   //this resource according to the index
00665   //
00666   if (nimages_>1)
00667   {
00668     if (TIFFSetDirectory(t_.tif(), index_)<=0)
00669       return 0;
00670     vil_tiff_header* h = new vil_tiff_header(t_.tif());
00671     //Cast away const
00672     vil_tiff_image* ti = (vil_tiff_image*)this;
00673     delete h_;
00674     ti->h_=h;
00675   }
00676 
00677   vil_image_view_base_sptr view = 0;
00678 
00679   //allocate input memory
00680   // input memory
00681   unsigned encoded_block_size = h_->encoded_bytes_per_block();
00682   assert(encoded_block_size>0);
00683   vxl_byte* data = new vxl_byte[encoded_block_size];
00684 
00685   //compute the block index
00686   unsigned blk_indx = this->block_index(block_index_i, block_index_j);
00687 
00688 
00689   vil_pixel_format fmt = vil_pixel_format_component_format(h_->pix_fmt);
00690 
00691   // input memory chunk
00692   vil_memory_chunk_sptr buf =
00693     new vil_memory_chunk(encoded_block_size, fmt);
00694   unsigned expanded_sample_bytes = vil_pixel_format_sizeof_components(fmt);
00695 
00696 
00697   if (h_->is_tiled())
00698   {
00699     if (TIFFReadEncodedTile(t_.tif(), blk_indx, data, (tsize_t) -1)<=0)
00700     {
00701       delete [] data;
00702       return view;
00703     }
00704     this->copy_byte_block(data, encoded_block_size, buf);
00705     delete [] data;
00706     if (h_->need_byte_swap())
00707       endian_swap( reinterpret_cast<vxl_byte*>(buf->data()),
00708                    encoded_block_size,
00709                    expanded_sample_bytes);
00710     return this->fill_block_from_tile(buf);
00711   }
00712 
00713   if (h_->is_striped())
00714   {
00715     if (TIFFReadEncodedStrip(t_.tif(), blk_indx, data, (tsize_t) -1)<=0)
00716     {
00717       delete [] data;
00718       return view;
00719     }
00720     this->copy_byte_block(data, encoded_block_size, buf);
00721     delete [] data;
00722     if (h_->need_byte_swap())
00723       endian_swap( reinterpret_cast<vxl_byte*>(buf->data()),
00724                    encoded_block_size,
00725                    expanded_sample_bytes);
00726     return this->fill_block_from_strip(buf);
00727   }
00728 
00729   return view;
00730 }
00731 
00732 //decode tiles: the tile is a contiguous raster scan of potentially
00733 //interleaved samples. This is an easy case since the tile is a
00734 //contiguous raster scan.
00735 vil_image_view_base_sptr vil_tiff_image::
00736 fill_block_from_tile(vil_memory_chunk_sptr const & buf) const
00737 {
00738   vil_image_view_base_sptr view = 0;
00739 
00740   //the size of the buffer when expanded to byte representation
00741   unsigned samples_per_block = this->samples_per_block();
00742   assert(samples_per_block>0);
00743 
00744   vil_pixel_format fmt = vil_pixel_format_component_format(h_->pix_fmt);
00745   view = view_from_buffer(fmt, buf, samples_per_block, h_->bits_per_sample.val);
00746   return view;
00747 }
00748 
00749 // decode strips.  The strip is somewhat different from the tile in that
00750 // it is organized around scan lines. If bits_per_pixel is not a integral
00751 // number of bytes then the last packed byte in the scan line will be only
00752 // partially filled. The header function, bytes_per_line() gives the actual
00753 // size of a scan line in the packed strip. The total size of the strip
00754 // in bytes is normally size_block_j()*bytes_per_line() but the last strip
00755 // may be truncated.
00756 vil_image_view_base_sptr vil_tiff_image::fill_block_from_strip(vil_memory_chunk_sptr const & buf) const
00757 {
00758   vil_image_view_base_sptr view = 0;
00759   vxl_uint_32 tl = size_block_j();
00760 
00761   unsigned bpl = h_->bytes_per_line();
00762   unsigned bytes_per_strip = h_->bytes_per_strip();
00763   unsigned lines_per_strip = bytes_per_strip/bpl;
00764 
00765   vil_pixel_format fmt = vil_pixel_format_component_format(h_->pix_fmt);
00766   unsigned expanded_bytes_per_sample =
00767     vil_pixel_format_sizeof_components(fmt);
00768   unsigned spl = h_->samples_per_line();
00769   unsigned bytes_expanded_line = spl*expanded_bytes_per_sample;
00770   //note here we make the last strip a full sized block to avoid
00771   //the messyness of multiple block sizes
00772   unsigned expanded_bytes_per_strip = tl*bytes_expanded_line;
00773 
00774   //pointer into the input packed strip buffer
00775   vxl_byte* buf_ptr = reinterpret_cast<vxl_byte*>(buf->data());
00776 
00777   //buffer for each scan line
00778   vil_memory_chunk_sptr line_buf =
00779     new vil_memory_chunk(bpl, fmt);
00780 
00781   //a buffer of zeros for filling partial strips to tile size
00782   vil_memory_chunk_sptr zero_buf =
00783     new vil_memory_chunk(bytes_expanded_line, fmt);
00784   vxl_byte* zero_ptr = reinterpret_cast<vxl_byte*>(zero_buf->data());
00785   for (unsigned i = 0; i<bytes_expanded_line; ++i)
00786     zero_ptr[i]=0;
00787 
00788   //buffer for the final unpacked output block
00789   vil_memory_chunk_sptr block_buf =
00790     new vil_memory_chunk(expanded_bytes_per_strip, fmt);
00791   vxl_byte* block_ptr = reinterpret_cast<vxl_byte*>(block_buf->data());
00792   //read scan lines from the strip and paste into the block
00793   for (unsigned j = 0; j<tl; ++j, buf_ptr+=bpl,
00794        block_ptr+=bytes_expanded_line)
00795   {
00796     if (j<lines_per_strip)
00797     {
00798       // get a row from the input buffer
00799       copy_byte_block(buf_ptr, bpl, line_buf);
00800       vil_memory_chunk_sptr out_line_buf;
00801       switch (fmt)
00802       {
00803 #define GET_LINE_CASE(FORMAT, T) \
00804        case FORMAT:\
00805         out_line_buf = \
00806           tiff_maybe_byte_align_data<T>(line_buf,\
00807                                         spl, h_->bits_per_sample.val,\
00808                                         bytes_expanded_line); \
00809         break
00810         GET_LINE_CASE(VIL_PIXEL_FORMAT_BYTE, vxl_byte);
00811         GET_LINE_CASE(VIL_PIXEL_FORMAT_SBYTE, vxl_sbyte);
00812 #if VXL_HAS_INT_64
00813         GET_LINE_CASE(VIL_PIXEL_FORMAT_UINT_64, vxl_uint_64);
00814         GET_LINE_CASE(VIL_PIXEL_FORMAT_INT_64, vxl_int_64);
00815 #endif
00816         GET_LINE_CASE(VIL_PIXEL_FORMAT_UINT_32, vxl_uint_32);
00817         GET_LINE_CASE(VIL_PIXEL_FORMAT_INT_32, vxl_int_32);
00818         GET_LINE_CASE(VIL_PIXEL_FORMAT_UINT_16, vxl_uint_16);
00819         GET_LINE_CASE(VIL_PIXEL_FORMAT_INT_16, vxl_int_16);
00820         GET_LINE_CASE(VIL_PIXEL_FORMAT_BOOL, bool);
00821         GET_LINE_CASE(VIL_PIXEL_FORMAT_FLOAT, float);
00822         GET_LINE_CASE(VIL_PIXEL_FORMAT_DOUBLE, double);
00823 #undef GET_LINE_CASE
00824        default:
00825         assert(!"Unknown vil data type in tiff file format");
00826         break;
00827       }
00828       //now we have the unpacked scan line in out_buf so copy to the view
00829       //buffer.
00830       vxl_byte* out_line_buf_ptr =
00831         reinterpret_cast<vxl_byte*>(out_line_buf->data());
00832       vcl_memcpy(block_ptr, out_line_buf_ptr, bytes_expanded_line);
00833     }
00834     else
00835       vcl_memcpy(block_ptr, zero_ptr, bytes_expanded_line);
00836   }
00837 
00838   return this->view_from_buffer(fmt, block_buf, spl*tl,
00839                                 expanded_bytes_per_sample*8);
00840 }
00841 
00842 void vil_tiff_image::pad_block_with_zeros(unsigned ioff, unsigned joff,
00843                                           unsigned iclip, unsigned jclip,
00844                                           unsigned bytes_per_pixel,
00845                                           vxl_byte* block_buf)
00846 {
00847   unsigned jstep = size_block_i()*bytes_per_pixel;
00848   unsigned row_start = ioff*bytes_per_pixel;
00849   unsigned bptr = 0;
00850   //fill leading part with zeroes
00851   if (ioff>0||joff>0)
00852     for (unsigned j = 0; j<joff-1; ++j)
00853     {
00854       unsigned row_ptr = row_start;
00855       for (unsigned i = 0; i<ioff-1; ++i)
00856       {
00857         for (unsigned p = 0; p<nplanes(); ++p)
00858           *(block_buf + bptr + row_ptr + p) = 0;
00859         row_ptr += bytes_per_pixel;
00860       }
00861       bptr += jstep;
00862     }
00863   bptr = jstep*jclip;
00864   row_start = iclip*bytes_per_pixel;
00865   if (iclip>0||jclip>0)
00866     for (unsigned j = jclip; j<size_block_j(); ++j)
00867     {
00868       unsigned row_ptr = row_start;
00869       for (unsigned i = iclip; i<size_block_i(); ++i)
00870       {
00871         for (unsigned p = 0; p<nplanes(); ++p)
00872           *(block_buf + bptr + row_ptr + p) = 0;
00873         row_ptr += bytes_per_pixel;
00874       }
00875       bptr += jstep;
00876     }
00877 }
00878 
00879 void vil_tiff_image::fill_block_from_view(unsigned bi, unsigned bj,
00880                                           unsigned i0, unsigned j0,
00881                                           unsigned ioff, unsigned joff,
00882                                           unsigned iclip, unsigned jclip,
00883                                           const vil_image_view_base& im,
00884                                           vxl_byte*& block_buf)
00885 {
00886   unsigned bytes_per_sample = h_->bytes_per_sample();
00887   unsigned bytes_per_pixel = bytes_per_sample*nplanes();
00888   unsigned sbi = size_block_i(), sbj = size_block_j();
00889   unsigned bytes_per_block=bytes_per_pixel*sbi*sbj;
00890   unsigned view_i0 = bi*sbi-i0, view_j0 = bj*sbj-j0;
00891   unsigned block_jstep = sbi*bytes_per_pixel;
00892 #if 0
00893   //Causes warnings. Leave here to document default values
00894   unsigned view_istep = 1, view_jstep = im.ni()*bytes_per_pixel, view_pstep = 1;
00895 #endif
00896   vcl_ptrdiff_t view_istep, view_jstep, view_pstep;
00897   vxl_byte* view_buf;
00898   //Cast the pixel type and reinterpret upper_left_ptr as a byte array.
00899   switch (h_->pix_fmt)
00900   {
00901 #define GET_VIEW_PTR(FORMAT, T) \
00902    case FORMAT: { \
00903     vil_image_view<T> view = static_cast<const vil_image_view<T>& >(im);\
00904     view_istep = view.istep(); view_jstep = view.jstep(); view_pstep = view.planestep(); \
00905     view_buf = reinterpret_cast<vxl_byte*>(view.top_left_ptr());\
00906    } break
00907     GET_VIEW_PTR(VIL_PIXEL_FORMAT_BYTE, vxl_byte);
00908     GET_VIEW_PTR(VIL_PIXEL_FORMAT_SBYTE, vxl_sbyte);
00909 #if VXL_HAS_INT_64
00910     GET_VIEW_PTR(VIL_PIXEL_FORMAT_UINT_64, vxl_uint_64);
00911     GET_VIEW_PTR(VIL_PIXEL_FORMAT_INT_64, vxl_int_64);
00912 #endif
00913     GET_VIEW_PTR(VIL_PIXEL_FORMAT_UINT_32, vxl_uint_32);
00914     GET_VIEW_PTR(VIL_PIXEL_FORMAT_INT_32, vxl_int_32);
00915     GET_VIEW_PTR(VIL_PIXEL_FORMAT_UINT_16, vxl_uint_16);
00916     GET_VIEW_PTR(VIL_PIXEL_FORMAT_INT_16, vxl_int_16);
00917     GET_VIEW_PTR(VIL_PIXEL_FORMAT_BOOL, bool);
00918     GET_VIEW_PTR(VIL_PIXEL_FORMAT_FLOAT, float);
00919     GET_VIEW_PTR(VIL_PIXEL_FORMAT_DOUBLE, double);
00920 #undef GET_VIEW_PTR
00921    default:
00922     assert(!"Unknown vil data type.");
00923     return;
00924   }
00925   //initial index into block buffer
00926   unsigned bptr = joff*block_jstep;
00927   unsigned ibstart = ioff*bytes_per_pixel;
00928   vcl_ptrdiff_t vistp = view_istep*bytes_per_sample;
00929   vcl_ptrdiff_t vjstp = view_jstep*bytes_per_sample;
00930   vcl_ptrdiff_t vpstp = view_pstep*bytes_per_sample;
00931   //initial index into view buffer
00932   // note that it is necessary to add the offset to the start of the
00933   // current block within the view, (view_i0, view_j0)
00934   vcl_ptrdiff_t vptr = (view_j0 + joff)*vjstp;
00935   unsigned ivstart = (view_i0 + ioff)*bytes_per_pixel;
00936   for (unsigned j = joff; j<jclip; ++j)
00937   {
00938     vcl_ptrdiff_t vrow_ptr = ivstart;
00939     vcl_ptrdiff_t brow_ptr = ibstart;
00940     for (unsigned i = ioff; i<iclip; ++i)
00941     {
00942       vcl_ptrdiff_t bpptr = 0, vpptr = 0;
00943       for (unsigned p = 0; p<nplanes(); ++p)
00944       {
00945         for (unsigned b = 0; b<bytes_per_sample; ++b)
00946           *(block_buf + bptr + brow_ptr + bpptr + b) =
00947             *(view_buf + vptr + vrow_ptr + vpptr + b);
00948         bpptr += bytes_per_sample; vpptr += vpstp;
00949       }
00950       brow_ptr += bytes_per_pixel; vrow_ptr += vistp;
00951     }
00952     bptr += block_jstep; vptr += vjstp;
00953   }
00954 
00955   //handle the case of bool  (other packed formats not supported for writing)
00956   if (this->pixel_format() == VIL_PIXEL_FORMAT_BOOL)
00957   {
00958     unsigned outsize = (bytes_per_block+7*sizeof(bool))/(8*sizeof(bool));
00959     vxl_byte* outbuf = new vxl_byte[outsize];
00960     this->bitpack_block(bytes_per_block, block_buf, outbuf);
00961     delete [] block_buf;
00962     block_buf = outbuf; // bytes_per_block=outsize;
00963   }
00964 }
00965 
00966 bool vil_tiff_image::write_block_to_file(unsigned bi, unsigned bj,
00967                                          unsigned block_size_bytes,
00968                                          vxl_byte* block_buf)
00969 {
00970   unsigned blk_indx = this->block_index(bi, bj);
00971   if (h_->is_tiled())
00972     return TIFFWriteEncodedTile(t_.tif(), blk_indx, block_buf,
00973                                 block_size_bytes)>0;
00974   if (h_->is_striped())
00975     return TIFFWriteEncodedStrip(t_.tif(), blk_indx, block_buf,
00976                                  block_size_bytes ) > 0;
00977   return false;
00978 }
00979 
00980 // Just support packing of bool data for now
00981 // ultimately we need the opposite of maybe_byte_align_data
00982 void vil_tiff_image::bitpack_block(unsigned bytes_per_block,
00983                                    vxl_byte* in_block_buf,
00984                                    vxl_byte* out_block_buf)
00985 {
00986   unsigned bytes_per_bool = sizeof(bool);
00987   vxl_byte* bl = new vxl_byte[bytes_per_bool];
00988   unsigned bitctr = 0;
00989   unsigned outctr = 0;
00990   vxl_byte packed_byte=0;
00991   for (unsigned i = 0; i<bytes_per_block; )
00992   {
00993     //test for a completed packed byte
00994     if (bitctr==8)
00995     {
00996       bitctr = 0;
00997       out_block_buf[outctr] = packed_byte;
00998       packed_byte = 0;
00999       ++outctr;
01000     }
01001     //pack a bool into the next bit
01002     for (unsigned b = 0; b<bytes_per_bool; ++b)
01003       bl[b] = *(in_block_buf + i + b);
01004     bool blv = *(reinterpret_cast<bool*>(bl));
01005     if (blv)
01006       packed_byte |= vxl_byte(1<<(7-bitctr)); //set a "1"
01007     else
01008       packed_byte &= vxl_byte(~(1<<(7-bitctr)));//set a "0"
01009     ++bitctr;
01010 
01011     i+=bytes_per_bool;
01012     if (i>=bytes_per_block) //output last (partial) byte
01013       out_block_buf[outctr] = packed_byte;
01014   }
01015   delete [] bl;
01016 }
01017 
01018 //an internal form of put_block for convenience
01019 //write the indicated block to file, padding with zeros if necessary
01020 //image view im is an arbitrary region of image that has to be decomposed into
01021 //blocks. The resource is written with zeros if the input view doesn't
01022 //correspond to exact block boundaries.  Subsequent put_view calls could
01023 //fill in the missing image data.
01024 bool vil_tiff_image::put_block(unsigned bi, unsigned bj, unsigned i0,
01025                                unsigned j0, const vil_image_view_base& im)
01026 {
01027   //Get the block offset and clipping parameters
01028 
01029   //ioff and joff are the offsets within a block to the start of valid data
01030   unsigned ioff =0, joff = 0;
01031   unsigned sbi = size_block_i(), sbj = size_block_j();
01032   unsigned iclip =sbi , jclip = sbj;
01033   //column offset into block. fill [0->ioff-1]
01034   if (bi*sbi<i0&&(bi+1)*sbi>i0)
01035     if (!block_i_offset(bi, i0, ioff))
01036       return false;
01037   //row offset into block fill [0->joff-1]
01038   if (bj*sbj<j0&&(bj+1)*sbj>j0)
01039     if (!block_j_offset(bj, j0, joff))
01040       return false;
01041 
01042   //iclip and jclip are the start of invalid data at the right and
01043   //bottom of partially filled blocks
01044 
01045   //right block margin to be padded [iclip -> size_block_i()-1]
01046   if ( (bi+1)*sbi > (im.ni()+i0) )
01047   {
01048     iclip = (i0+im.ni())-bi*sbi;
01049     if (iclip > sbi)
01050       return false;
01051   }
01052 
01053   //bottom block margin to be padded [jclip -> size_block_j()-1]
01054   if ( (bj+1)*sbj > (im.nj()+j0) )
01055   {
01056     jclip = (j0+im.nj())-bj*sbj;
01057     if (jclip > sbj)
01058       return false;
01059   }
01060   unsigned bps = h_->bytes_per_sample();
01061   unsigned bytes_per_pixel = bps*nplanes();
01062 
01063   unsigned bytes_per_block = bytes_per_pixel*sbi*sbj;
01064 
01065 
01066   //the data buffer for the block
01067   vxl_byte* block_buf = new vxl_byte[bytes_per_block];
01068 
01069   this->pad_block_with_zeros(ioff, joff, iclip, jclip,
01070                              bytes_per_pixel, block_buf);
01071 
01072 
01073   this->fill_block_from_view(bi, bj, i0, j0, ioff, joff, iclip, jclip,
01074                              im, block_buf);
01075   //write the block to the tiff file
01076   bool good_write = write_block_to_file(bi, bj, bytes_per_block, block_buf);
01077   delete [] block_buf;
01078   return good_write;
01079 }
01080 
01081 bool vil_tiff_image::put_view(const vil_image_view_base& im,
01082                               unsigned i0, unsigned j0)
01083 {
01084   if (!vil_image_resource::view_fits(im, i0, j0))
01085   {
01086     vil_exception_warning(vil_exception_out_of_bounds("vil_tiff_image::put_view"));
01087     return false;
01088   }
01089 
01090   unsigned tw = size_block_i(), tl = size_block_j();
01091   if (tw==0||tl==0)
01092     return false;
01093   unsigned  bi_start = i0/tw, bi_end = (i0+im.ni()-1)/tw;
01094   unsigned  bj_start = j0/tl, bj_end = (j0+im.nj()-1)/tl;
01095   for (unsigned bi = bi_start; bi<=bi_end; ++bi)
01096     for (unsigned bj = bj_start; bj<=bj_end; ++bj)
01097       if (!this->put_block(bi, bj, i0, j0, im))
01098         return false;
01099   return true;
01100 }
01101 
01102 // The virtual put_block method. In this case the view is a complete block
01103 bool vil_tiff_image::put_block( unsigned  block_index_i,
01104                                 unsigned  block_index_j,
01105                                 const vil_image_view_base& blk )
01106 {
01107   if (blk.ni()==0||blk.nj()==0)
01108     return false;
01109   unsigned sbi = this->size_block_i(), sbj = this->size_block_j();
01110   unsigned bps = h_->bytes_per_sample();
01111   unsigned bytes_per_pixel = bps*nplanes();
01112 
01113   unsigned bytes_per_block = bytes_per_pixel*sbi*sbj;
01114 
01115   //the data buffer for the block
01116   vxl_byte* block_buf = new vxl_byte[bytes_per_block];
01117 
01118   this->fill_block_from_view(0, 0, 0, 0, 0, 0,sbi, sbj, blk, block_buf);
01119 
01120   //write the block to the tiff file
01121   bool good_write = write_block_to_file(block_index_i, block_index_j, bytes_per_block, block_buf);
01122   delete [] block_buf;
01123   return good_write;
01124 }
01125 
01126 //Begin pyramid resource
01127 static bool level_compare(tiff_pyramid_level* const l1, tiff_pyramid_level* const l2)
01128 {
01129   assert(l1&&l2);
01130   return l1->ni_ > l2->ni_;
01131 }
01132 
01133 //: Assumes that the image in level 0 is the largest
01134 void vil_tiff_pyramid_resource::normalize_scales()
01135 {
01136   unsigned nlevels = this->nlevels();
01137   if (nlevels==0)
01138     return;
01139   levels_[0]->scale_ = 1.0f;
01140   if (nlevels==1)
01141     return;
01142   float ni0 = static_cast<float>(levels_[0]->ni_);
01143   for (unsigned i = 1; i<nlevels; ++i)
01144     levels_[i]->scale_ = static_cast<float>(levels_[i]->ni_)/ni0;
01145 }
01146 
01147 //:find the level closest to the specified scale
01148 tiff_pyramid_level* vil_tiff_pyramid_resource::closest(const float scale) const
01149 {
01150   unsigned nlevels = this->nlevels();
01151   if (nlevels == 0)
01152     return 0;
01153   if (nlevels == 1)
01154     return levels_[0];
01155   float mind = 1.0e08f;//huge scale;
01156   unsigned lmin = 0;
01157   for (unsigned i = 0; i<nlevels; ++i)
01158   {
01159     float ds = vcl_fabs(scale - levels_[i]->scale_);
01160     if (ds<mind)
01161     {
01162       mind = ds;
01163       lmin = i;
01164     }
01165   }
01166   tiff_pyramid_level* pl = levels_[lmin];
01167   if (pl)
01168     pl->cur_level_ = lmin;
01169   return pl;
01170 }
01171 
01172 vil_tiff_pyramid_resource::vil_tiff_pyramid_resource()
01173   : read_(true), t_(0)
01174 {
01175 }
01176 
01177 vil_tiff_pyramid_resource::
01178 vil_tiff_pyramid_resource(tif_smart_ptr const& t, bool read)
01179   : read_(read), t_(t)
01180 {
01181   bool trace = false;
01182   if (!read)
01183     return;
01184   //for reading we need to set up the levels
01185   while (true)
01186   {
01187     vil_tiff_header h(t_.tif());
01188     if (trace)
01189       vcl_cerr << "In vil_tiff_pyramid_resource constructor"
01190                << " constructed header\n"
01191                << "n-levels = " << this->nlevels() << '\n';
01192     tiff_pyramid_level* pl = new tiff_pyramid_level(this->nlevels(),
01193                                                     h.image_width.val,
01194                                                     h.image_length.val,
01195                                                     h.nplanes,
01196                                                     h.pix_fmt);
01197     levels_.push_back(pl);
01198     if (trace)
01199       vcl_cerr << "In vil_tiff_pyramid_resource constructor"
01200                << " constructed level\n";
01201     int status = TIFFReadDirectory(t_.tif());
01202     if (trace)
01203       vcl_cerr << "In vil_tiff_pyramid_resource constructor"
01204                << " Read new directory\n";
01205 
01206     if (!status)
01207       break;
01208   }
01209   if (trace)
01210     vcl_cerr << "In vil_tiff_pyramid_resource constructor"
01211              << " Begin sorting\n";
01212   //sort the pyramid
01213   vcl_sort(levels_.begin(), levels_.end(), level_compare);
01214   //normalize the scales
01215   this->normalize_scales();
01216 }
01217 
01218 vil_tiff_pyramid_resource::~vil_tiff_pyramid_resource()
01219 {
01220   for (unsigned L = 0; L<this->nlevels(); ++L)
01221     delete levels_[L];
01222 }
01223 
01224 //:Get a partial view from the image from a specified pyramid level
01225 vil_image_view_base_sptr
01226 vil_tiff_pyramid_resource::get_copy_view(unsigned i0, unsigned n_i,
01227                                          unsigned j0, unsigned n_j,
01228                                          unsigned level) const
01229 {
01230   unsigned nl = this->nlevels();
01231   if (level>=nl)
01232     return vil_image_view_base_sptr();
01233   vil_image_resource_sptr resc = this->get_resource(level);
01234   //scale input coordinates to the scale of the level
01235   float scale = levels_[level]->scale_;
01236   float fi0 = vcl_floor(scale*i0), fj0 = vcl_floor(scale*j0);
01237   float fni = vcl_floor(scale*n_i), fnj = vcl_floor(scale*n_j);
01238   unsigned si0 = static_cast<unsigned>(fi0);
01239   unsigned sj0 = static_cast<unsigned>(fj0);
01240   unsigned sni = static_cast<unsigned>(fni);
01241   if (sni == 0) sni = 1;//can't have less than one pixel
01242   unsigned snj = static_cast<unsigned>(fnj);
01243   if (snj == 0) snj = 1;//can't have less than one pixel
01244   vil_image_view_base_sptr view = resc->get_copy_view(si0, sni, sj0, snj);
01245 #if 0 //DON'T NEED CLEAR?
01246   resc->clear_TIFF();
01247 #endif
01248   return view;
01249 }
01250 
01251 //:Get a partial view from the image in the pyramid closest to scale.
01252 // The origin and size parameters are in the coordinate system
01253 // of the base image. The scale factor is with respect to the base
01254 // image (base scale = 1.0).
01255 vil_image_view_base_sptr
01256 vil_tiff_pyramid_resource::get_copy_view(unsigned i0, unsigned n_i,
01257                                          unsigned j0, unsigned n_j,
01258                                          const float scale,
01259                                          float& actual_scale) const
01260 {
01261   // Get the closest scale
01262   tiff_pyramid_level* pl  = this->closest(scale);
01263   if (!pl)
01264     return 0;
01265   actual_scale = pl->scale_;
01266   return this->get_copy_view(i0, n_i, j0, n_j, pl->cur_level_);
01267 }
01268 
01269 //: Put the data in this view back into the image source at specified level.
01270 // Only can be written once.
01271 bool vil_tiff_pyramid_resource::put_resource(vil_image_resource_sptr const& ir)
01272 {
01273   unsigned level = this->nlevels();
01274   unsigned ni = ir->ni(), nj = ir->nj();
01275   unsigned nplanes = ir->nplanes();
01276   vil_pixel_format fmt = ir->pixel_format();
01277   vil_blocked_image_resource_sptr bir = blocked_image_resource(ir);
01278   unsigned sbi = 0, sbj = 0;
01279   if (bir) { sbi = bir->size_block_i(); sbj = bir->size_block_j(); }
01280   // setup the image header for the level
01281   vil_tiff_header* h = new vil_tiff_header(t_.tif(), ni, nj, nplanes,
01282                                            fmt, sbi, sbj);
01283 
01284   /* We are writing single page of the multipage file */
01285   TIFFSetField(t_.tif(), TIFFTAG_SUBFILETYPE, FILETYPE_PAGE);
01286   /* Set the page number */
01287   TIFFSetField(t_.tif(), TIFFTAG_PAGENUMBER,level, 3);
01288   vil_tiff_image* ti = new vil_tiff_image(t_, h, level);
01289   vil_image_resource_sptr resc = ti;
01290   if (!vil_copy_deep(ir, resc))
01291     return false;
01292 #if 0 //DON'T NEED CLEAR?
01293   ti->clear_TIFF();
01294 #endif
01295   tiff_pyramid_level* pl = new tiff_pyramid_level(levels_.size(), ni, nj, nplanes, fmt);
01296   levels_.push_back(pl);
01297   int status = TIFFWriteDirectory(t_.tif());
01298   return status == 1 ;
01299 }
01300 //: returns the pyramid resource at the specified level
01301 vil_image_resource_sptr vil_tiff_pyramid_resource::get_resource(const unsigned level) const
01302 {
01303   unsigned nl = this->nlevels();
01304   if (level>=nl)
01305     return 0;
01306   // setup the image header for the level
01307   unsigned header_index = levels_[level]->header_index_;
01308   // The status value should be checked here
01309   if (TIFFSetDirectory(t_.tif(), header_index)<=0)
01310     return 0;
01311   vil_tiff_header* h = new vil_tiff_header(t_.tif());
01312   vil_tiff_image* i = new vil_tiff_image(t_, h, nl);
01313   i->set_index(header_index);
01314   return i;
01315 }

Generated on Mon Nov 23 05:08:35 2009 for core/vil by  doxygen 1.5.1