core/vil/file_formats/vil_nitf2_image.cxx

Go to the documentation of this file.
00001 // vil_nitf2: Written by Rob Radtke (rob@) and Harry Voorhees (hlv@) of
00002 // Stellar Science Ltd. Co. (stellarscience.com) for
00003 // Air Force Research Laboratory, 2005.
00004 
00005 #include "vil_nitf2_image.h"
00006 
00007 //:
00008 // \file
00009 
00010 #include <vcl_cassert.h>
00011 #include <vcl_cstring.h> // for std::memcpy()
00012 #include <vcl_algorithm.h>
00013 #include <vcl_cstdlib.h>
00014 #include <vil/vil_stream_fstream.h>
00015 #include <vil/vil_image_view.h>
00016 #include <vil/vil_property.h>
00017 #include "vil_nitf2_data_mask_table.h"
00018 #include "vil_nitf2_des.h"
00019 
00020 #if HAS_J2K
00021 #include "vil_j2k_image.h"
00022 #endif //HAS_J2K
00023 
00024 int debug_level = 0;
00025 
00026 //--------------------------------------------------------------------------------
00027 // class vil_nitf2_file_format
00028 
00029 static char const nitf2_string[] = "nitf";
00030 
00031 char const* vil_nitf2_file_format::tag() const
00032 {
00033   return nitf2_string;
00034 }
00035 
00036 vil_image_resource_sptr  vil_nitf2_file_format::make_input_image(vil_stream *vs)
00037 {
00038   vil_nitf2_image* im = new vil_nitf2_image( vs );
00039   if ( !im->parse_headers() ) {
00040     delete im;
00041     im = 0;
00042   }
00043   return im;
00044 }
00045 
00046 vil_image_resource_sptr
00047   vil_nitf2_file_format::make_output_image(vil_stream* /*vs*/,
00048                                            unsigned /*nx*/,
00049                                            unsigned /*ny*/,
00050                                            unsigned /*nplanes*/,
00051                                            enum vil_pixel_format /*format*/)
00052 {
00053   //write not supported
00054   return 0;
00055 }
00056 
00057 //--------------------------------------------------------------------------------
00058 // class vil_nitf2_image
00059 
00060 vil_streampos vil_nitf2_image::get_offset_to( vil_nitf2_header::section_type sec,
00061                                               vil_nitf2_header::portion_type por,
00062                                               unsigned int index ) const
00063 {
00064   vil_streampos p;
00065   if ( sec == vil_nitf2_header::enum_file_header ) {
00066     //there is no data section in the file header and
00067     //there is only one
00068     assert( por == vil_nitf2_header::enum_subheader );
00069     assert( index == 0 );
00070     //file header is the first thing
00071     p = 0;
00072   } else {
00073     vil_nitf2_header::section_type preceding_section = (vil_nitf2_header::section_type)(sec-1);
00074     p = get_offset_to( preceding_section, vil_nitf2_header::enum_subheader, 0 ) +
00075         size_to( preceding_section, vil_nitf2_header::enum_subheader, -1 ) +
00076         size_to( sec, por, index );
00077   }
00078   return p;
00079 }
00080 
00081 vil_streampos vil_nitf2_image::size_to(vil_nitf2_header::section_type sec,
00082                                        vil_nitf2_header::portion_type por,
00083                                        int index ) const
00084 {
00085   if ( sec == vil_nitf2_header::enum_file_header ) {
00086     if ( index == -1 ) {
00087       int file_header_size;
00088       m_file_header.get_property("HL", file_header_size);
00089       return (vil_streampos)file_header_size;
00090     } else {
00091       return 0;
00092     }
00093   }
00094 
00095   vil_streampos offset = 0;
00096   //if -1 specified, then we want to go past all of them... that is onto the next
00097   //section
00098   bool going_past_end = false;
00099   if ( index == -1 ) {
00100     int num_segments;
00101     m_file_header.get_property(vil_nitf2_header::section_num_tag(sec), num_segments);
00102     index = num_segments;
00103     going_past_end = true;
00104   }
00105   vcl_string sh = vil_nitf2_header::section_len_header_tag( sec );
00106   vcl_string s  = vil_nitf2_header::section_len_data_tag( sec );
00107   int i;
00108   for (i = 0 ; i < index ; i++) {
00109     int current_header_size;
00110     m_file_header.get_property(sh, i, current_header_size);
00111     offset += current_header_size;
00112     if ( sec == vil_nitf2_header::enum_image_segments ){
00113       vil_nitf2_long current_data_size;
00114       m_file_header.get_property(s, i, current_data_size);
00115       offset += current_data_size;
00116     } else {
00117       int current_data_size;
00118       m_file_header.get_property(s, i, current_data_size);
00119       offset += current_data_size;
00120     }
00121   }
00122   //we are now at the proper index's subheader... if we need to get to the data
00123   //we've got one more jump to do
00124   if ( por == vil_nitf2_header::enum_data ) {
00125     // if we've skipped past all the segments, then it doesn't make any sense
00126     // to skip to the "data" section
00127     if ( going_past_end ) { assert(!"skipped past all segments"); return 0L; }
00128     int current_header_size;
00129     m_file_header.get_property(sh, i, current_header_size);
00130     offset += current_header_size;
00131   }
00132   return offset;
00133 }
00134 
00135 vil_image_view_base_sptr ( *vil_nitf2_image::s_decode_jpeg_2000 )
00136 ( vil_stream* vs, unsigned i0, unsigned ni, unsigned j0, unsigned nj, double i_factor, double j_factor ) = 0;
00137 
00138 vil_nitf2_image::vil_nitf2_image(vil_stream* is)
00139   : m_stream(is),
00140     m_current_image_index(0)
00141 {
00142   m_stream->ref();
00143 }
00144 
00145 vil_nitf2_image::vil_nitf2_image(const vcl_string& filePath, const char* mode)
00146   : m_current_image_index(0)
00147 {
00148 #ifdef VIL_USE_FSTREAM64
00149   m_stream = new vil_stream_fstream64(filePath.c_str(), mode);
00150 #else //VIL_USE_FSTREAM64
00151   m_stream = new vil_stream_fstream(filePath.c_str(), mode);
00152 #endif //VIL_USE_FSTREAM64
00153   m_stream->ref();
00154 }
00155 
00156 void vil_nitf2_image::clear_image_headers()
00157 {
00158   for (unsigned int i = 0 ; i < m_image_headers.size() ; i++) {
00159     delete m_image_headers[i];
00160   }
00161   m_image_headers.clear();
00162 }
00163 
00164 void vil_nitf2_image::clear_des()
00165 {
00166   for (unsigned int i = 0 ; i < m_des.size() ; i++) {
00167     delete m_des[i];
00168   }
00169   m_des.clear();
00170 }
00171 
00172 
00173 vil_nitf2_image::~vil_nitf2_image()
00174 {
00175   m_stream->unref();
00176   clear_image_headers();
00177   clear_des();
00178 }
00179 
00180 unsigned int vil_nitf2_image::current_image() const
00181 {
00182   return m_current_image_index;
00183 }
00184 
00185 void vil_nitf2_image::set_current_image(unsigned int index)
00186 {
00187   assert(index < m_image_headers.size());
00188   m_current_image_index = index;
00189 }
00190 
00191 unsigned int vil_nitf2_image::nimages() const
00192 {
00193   int num_images;
00194   if (m_file_header.get_property("NUMI", num_images)) return num_images;
00195   else return 0;
00196 }
00197 
00198 vil_streampos vil_nitf2_image::get_offset_to_image_data_block_band(
00199   unsigned int image_index, unsigned int block_index_x,unsigned int block_index_y, int bandIndex) const
00200 {
00201   //band index is ignored when i_mode != "S"
00202   vcl_string i_mode;
00203   current_image_header()->get_property("IMODE", i_mode);
00204 
00205   //my image header precedes me.  Find out the offset to that, then add on the size of
00206   //that header... then you have the offset to me (the data)
00207   vil_streampos offset =
00208     get_offset_to( vil_nitf2_header::enum_image_segments, vil_nitf2_header::enum_data, image_index );
00209 
00210   //////////////////////////////////////////////////
00211   // now get the position to the desired block/band
00212   //////////////////////////////////////////////////
00213   int bits_per_pixel_per_band;
00214   current_image_header()->get_property("NBPP", bits_per_pixel_per_band);
00215 
00216 #if 0  //Not valid if blocks are partially filled (JLM 11/03/07)
00217   unsigned int bytes_per_band = ni() * nj() * bits_per_pixel_per_band / 8;
00218 #endif
00219   // New version
00220   unsigned int nbi = n_block_i(), nbj = n_block_j();
00221   unsigned int sbi = size_block_i(), sbj = size_block_j();
00222   unsigned int bytes_per_band = nbi*nbj*sbi*sbj*bits_per_pixel_per_band/8;
00223 
00224   // What we do here depends on whether we have a data_mask_table or not and
00225   // whether i_mode == "S".  The most complex case is i_mode != "S" and we have
00226   // a dataMask table.  In that case, we get some information from the table and
00227   // compute some ourselves.  Here are all the possible scenarios handled here:
00228   //   i_mode == "S" and have data_mask_table: just ask data_mask_table for the offset
00229   //   i_mode == "S" and don't have data_mask_table: compute it ourselves vcl_right here
00230   //   i_mode != "S" and have data_mask_table: ask the data_mask_table for offset to the
00231   //      block we want; then compute the offset to the band ourselves here
00232   //   i_mode != "S" and don't have data_mask_table: compute both band and block offset
00233   //      ourselves here
00234   // If it sounds complex, blame the NITF 2.1 spec for that
00235   const vil_nitf2_data_mask_table* data_mask_table = current_image_header()->data_mask_table();
00236   if (data_mask_table) {
00237     offset += data_mask_table->blocked_image_data_offset();
00238   }
00239   if (data_mask_table && data_mask_table->has_offset_table()) {
00240     //have data mask table
00241     int bI = i_mode == "S" ? bandIndex : -1;
00242     if (data_mask_table->block_band_present(block_index_x, block_index_y, bI))
00243     {
00244       return 0;
00245     }
00246     offset += data_mask_table->block_band_offset(block_index_x, block_index_y, bI);
00247   } else {
00248       unsigned int pixels_per_block = size_block_i() * size_block_j();
00249       unsigned int bits_per_band = pixels_per_block * bits_per_pixel_per_band;
00250       unsigned int bytes_per_block_per_band = bits_per_band / 8;
00251       //round up if remainder left over (this assumes that band/block boundaries
00252       //always lie on byte boundaries.
00253       if (bits_per_band % 8 != 0) bytes_per_block_per_band++;
00254     if (i_mode == "S") {
00255       //i_mode == "S" and not have data_mask_table
00256       unsigned int offset_to_desired_band = bandIndex * bytes_per_band;
00257       unsigned int offset_to_desired_block = bytes_per_block_per_band * (block_index_y * n_block_i() + block_index_x);
00258       offset += offset_to_desired_band + offset_to_desired_block;
00259     } else {
00260       //i_mode != "S" and not have data_mask_table
00261       unsigned int block_size_bytes = bytes_per_block_per_band * nplanes();
00262       unsigned int offset_to_desired_block = block_size_bytes * (block_index_y * n_block_i() + block_index_x);
00263       offset += offset_to_desired_block;
00264     }
00265   }
00266   if (i_mode != "S") {
00267     //regardless of whether we had a data_mask_table or not, we've only computed
00268     //the offset to the desired block so far.  Now, we add on the offset to
00269     //the desired band.
00270     unsigned int offset_to_desired_band = bandIndex * bytes_per_band;
00271     offset += offset_to_desired_band;
00272   }
00273   return offset;
00274 }
00275 
00276 bool vil_nitf2_image::parse_headers()
00277 {
00278   if (!m_stream->ok()) return false;
00279   //parse file header
00280   m_stream->seek(0);
00281   if (!m_file_header.read(m_stream)) {
00282     return false;
00283   }
00284   //now parse each image header
00285   clear_image_headers();
00286   m_image_headers.resize(nimages());
00287   for (unsigned int i = 0 ; i < nimages() ; i++) {
00288     vil_streampos offset = get_offset_to( vil_nitf2_header::enum_image_segments, vil_nitf2_header::enum_subheader, i);
00289     m_stream->seek(offset);
00290     m_image_headers[i] = new vil_nitf2_image_subheader(file_version());
00291     if (!m_image_headers[i]->read(m_stream)) return false;
00292   }
00293 
00294   //now parse all the DESs (if any)
00295   clear_des();
00296   int num_des;
00297   m_file_header.get_property( "NUMDES", num_des );
00298   m_des.resize( num_des );
00299   for ( int j = 0 ; j < num_des ; j++ ){
00300     vil_streampos offset = get_offset_to( vil_nitf2_header::enum_data_extension_segments, vil_nitf2_header::enum_subheader, j);
00301     m_stream->seek(offset);
00302     int data_width;
00303     m_file_header.get_property( "LD", j, data_width );
00304     m_des[j] = new vil_nitf2_des(file_version(), data_width);
00305     if (!m_des[j]->read(m_stream)) return false;
00306   }
00307   return true;
00308 }
00309 
00310 vil_nitf2_classification::file_version vil_nitf2_image::file_version() const
00311 {
00312   return m_file_header.file_version();
00313 }
00314 
00315 char const * vil_nitf2_image::file_format() const
00316 {
00317 vil_nitf2_classification::file_version v = file_version();
00318   switch (v)
00319     {
00320     case vil_nitf2_classification::V_UNKNOWN :
00321       return "unknown";
00322     case vil_nitf2_classification::V_NITF_10 :
00323       return "nitf10";
00324     case vil_nitf2_classification::V_NITF_20 :
00325       return "nitf20";
00326     case vil_nitf2_classification::V_NITF_21 :
00327       return "nitf21";
00328     default:
00329       return "unknown";
00330     }
00331 }
00332 
00333 const vil_nitf2_image_subheader* vil_nitf2_image::current_image_header() const
00334 {
00335   assert(m_current_image_index < m_image_headers.size());
00336   return m_image_headers[ m_current_image_index ];
00337 }
00338 
00339 unsigned vil_nitf2_image::nplanes() const
00340 {
00341   return current_image_header()->nplanes();
00342 }
00343 
00344 unsigned vil_nitf2_image::ni() const
00345 {
00346   //Note that we are choosing to return the number of significant columns
00347   //rather than NPPBH*NBPR which would be the total number of pixels in the
00348   //image.  if NPPBH*NBPR > NCOLS, then all the extra columns are blanked
00349   //out pad pixels.  Why would anyone want those?
00350   int num_significant_cols;
00351   if (current_image_header()->get_property("NCOLS", num_significant_cols))
00352   {
00353     return num_significant_cols;
00354   }
00355   return 0;
00356 }
00357 
00358 unsigned vil_nitf2_image::nj() const
00359 {
00360   //Note that we are choosing to return the number of significant rows
00361   //rather than NPPBV*NBPC which would be the total number of pixels in the
00362   //image.  if NPPBV*NBPC > NROWS, then all the extra columns are blanked
00363   //out pad pixels.  Why would anyone want those?
00364   int num_significant_rows;
00365   if (current_image_header()->get_property("NROWS", num_significant_rows))
00366   {
00367     return num_significant_rows;
00368   }
00369   return 0;
00370 }
00371 
00372 enum vil_pixel_format vil_nitf2_image::pixel_format () const
00373 {
00374   vcl_string pixel_type;
00375   int bits_per_pixel;
00376   if (current_image_header()->get_property("PVTYPE", pixel_type) &&
00377       current_image_header()->get_property("NBPP", bits_per_pixel))
00378   {
00379     //if bits_per_pixel isn't divisible by 8, round up to nearest byte
00380     int bytesPerPixel = bits_per_pixel / 8;
00381     if (bits_per_pixel % 8 != 0) bytesPerPixel++;
00382     bits_per_pixel = bytesPerPixel * 8;
00383     if (pixel_type == "INT") {
00384       if (bits_per_pixel == 8) {
00385         return VIL_PIXEL_FORMAT_BYTE;
00386       } else if (bits_per_pixel == 16) {
00387         return VIL_PIXEL_FORMAT_UINT_16;
00388       } else if (bits_per_pixel == 32) {
00389         return VIL_PIXEL_FORMAT_UINT_32;
00390       }
00391 #if VXL_HAS_INT_64
00392       else if (bits_per_pixel == 64) {
00393         return VIL_PIXEL_FORMAT_UINT_64;
00394       }
00395 #endif //VXL_HAS_INT_64
00396     } else if (pixel_type == "B") {
00397       return VIL_PIXEL_FORMAT_BOOL;
00398     } else if (pixel_type == "SI") {
00399       if (bits_per_pixel == 8) {
00400         return VIL_PIXEL_FORMAT_SBYTE;
00401       } else if (bits_per_pixel == 16) {
00402         return VIL_PIXEL_FORMAT_INT_16;
00403       } else if (bits_per_pixel == 32) {
00404         return VIL_PIXEL_FORMAT_INT_32;
00405       }
00406 #if VXL_HAS_INT_64
00407       else if (bits_per_pixel == 64) {
00408         return VIL_PIXEL_FORMAT_INT_64;
00409       }
00410 #endif //VXL_HAS_INT_64
00411     } else if (pixel_type == "R") {
00412       if (bits_per_pixel == 32) {
00413         return VIL_PIXEL_FORMAT_FLOAT;
00414       } else if (bits_per_pixel == 64) {
00415         return VIL_PIXEL_FORMAT_DOUBLE;
00416       }
00417     } else if (pixel_type == "C") {
00418       //two 32 bit floats (real followed by complex)
00419       if (bits_per_pixel == 64) {
00420         return VIL_PIXEL_FORMAT_COMPLEX_FLOAT;
00421       }// else if (bits_per_pixel == 64) {
00422        // return VIL_PIXEL_FORMAT_COMPLEX_DOUBLE;
00423       //}
00424     }
00425   }
00426   return VIL_PIXEL_FORMAT_UNKNOWN;
00427 }
00428 
00429 unsigned int vil_nitf2_image::size_block_i() const
00430 {
00431 return current_image_header()->get_pixels_per_block_x();
00432 }
00433 
00434 unsigned int vil_nitf2_image::size_block_j() const
00435 {
00436   return current_image_header()->get_pixels_per_block_y();
00437 }
00438 
00439 unsigned int vil_nitf2_image::n_block_i() const
00440 {
00441   return current_image_header()->get_num_blocks_x();
00442 }
00443 
00444 unsigned int vil_nitf2_image::n_block_j() const
00445 {
00446   return current_image_header()->get_num_blocks_y();
00447 }
00448 
00449 void  compute_block_and_offset(unsigned j0, unsigned long block_size,
00450                                unsigned int& block, unsigned int& offset)
00451 {
00452   block = 0;
00453   offset = 0;
00454 
00455   if (j0 != 0) {
00456     block = (j0 / block_size);
00457     if (j0 > 0 && j0 % block_size != 0) {
00458       offset = j0 - (block * block_size);
00459     }
00460   }
00461 }
00462 
00463 bool vil_nitf2_image::is_jpeg_2000_compressed() const
00464 {
00465   vcl_string compression_type;
00466   //ISO/IEC BIFF profile BPJ2k01.00 says that M8 is actually invalid
00467   //(ie. you can't use a data mask with jpeg 2000 compression)
00468   //not sure why it is an option though
00469   return ( current_image_header()->get_property("IC", compression_type) ) &&
00470          ( compression_type == "C8" || compression_type == "M8" );
00471 }
00472 
00473 vil_image_view_base_sptr vil_nitf2_image::get_copy_view_decimated_j2k(
00474   unsigned start_i, unsigned num_i, unsigned start_j, unsigned num_j, double i_factor, double j_factor ) const
00475 {
00476   // ACCORDING TO DOCUMENTATION, IF PARAMETERS ARE BAD, WE SHOULD RETURN NULL POINTER.
00477   if ((start_i + num_i > ni()) || (start_j + num_j > nj())) {
00478     return 0;
00479   }
00480   assert( is_jpeg_2000_compressed() );
00481   if ( ! s_decode_jpeg_2000 ) {
00482 #if HAS_J2K
00483     s_decode_jpeg_2000 = vil_j2k_image::s_decode_jpeg_2000;
00484 #else //HAS_J2K
00485     return 0;
00486 #endif //HAS_J2K
00487   }
00488 
00489   //it is my understanding from BIFF profile BPJ2k01.00 that JPEG compressed files
00490   //will only have on image block (ie. it will be clocked within the jp2 codestream),
00491   //so we can just pass all the work off to the vil_j2k_image class
00492   m_stream->seek(get_offset_to( vil_nitf2_header::enum_image_segments, vil_nitf2_header::enum_data, m_current_image_index));
00493   return s_decode_jpeg_2000( m_stream, start_i, num_i, start_j, num_j, i_factor, j_factor );
00494 }
00495 
00496 vil_image_view_base_sptr vil_nitf2_image::get_copy_view(unsigned start_i, unsigned num_i,
00497                                                         unsigned start_j, unsigned num_j) const
00498 {
00499   // ACCORDING TO DOCUMENTATION, IF PARAMETERS ARE BAD, WE SHOULD RETURN NULL POINTER.
00500   if ((start_i + num_i > ni()) || (start_j + num_j > nj())) {
00501     return 0;
00502   }
00503 
00504   vcl_string compression_type;
00505   if (!current_image_header()->get_property("IC", compression_type)) return 0;
00506 
00507   //right now we only plan to support uncompressed and JPEG2000
00508   if (compression_type == "NC" || compression_type == "NM") {
00509     return get_copy_view_uncompressed(start_i, num_i, start_j, num_j);
00510   } else if ( is_jpeg_2000_compressed() ) {
00511     return get_copy_view_decimated_j2k( start_i, num_i, start_j, num_j, 1.0, 1.0 );
00512   } else {
00513     return 0;
00514   }
00515 }
00516 
00517 vil_image_view_base_sptr vil_nitf2_image::get_copy_view_uncompressed(unsigned start_i, unsigned num_i,
00518                                                                      unsigned start_j, unsigned num_j) const
00519 {
00520   return vil_blocked_image_resource::get_copy_view(start_i, num_i, start_j, num_j);
00521 }
00522 
00523 template< class T >
00524 vil_memory_chunk_sptr maybe_byte_align_data(vil_memory_chunk_sptr in_data, unsigned int num_samples,
00525                                             unsigned int in_bits_per_sample, T /*dummy*/)
00526 {
00527   if (in_bits_per_sample != sizeof(T)*8) {
00528     vil_memory_chunk_sptr new_memory = new vil_memory_chunk(num_samples*sizeof(T), in_data->pixel_format());
00529     byte_align_data((T*)in_data->data(), num_samples, in_bits_per_sample, (T*)new_memory->data());
00530     return new_memory;
00531   }
00532   return in_data;
00533 }
00534 
00535 // don't do anything for float and double (bit shifting isn't allowed)
00536 template<> vil_memory_chunk_sptr maybe_byte_align_data<float> (
00537   vil_memory_chunk_sptr in_data, unsigned int /* num_samples */, unsigned int /* in_bits_per_sample */, float /*dummy*/)
00538 { return in_data; }
00539 
00540 template<> vil_memory_chunk_sptr maybe_byte_align_data<double> (
00541   vil_memory_chunk_sptr in_data, unsigned int /* num_samples */, unsigned int /* in_bits_per_sample */, double /*dummy*/)
00542 { return in_data; }
00543 
00544 template<> vil_memory_chunk_sptr maybe_byte_align_data< vcl_complex< float > > (
00545   vil_memory_chunk_sptr in_data, unsigned int /*num_samples*/, unsigned int /*in_bits_per_sample*/, vcl_complex<float> /*dummy*/)
00546 { return in_data; }
00547 
00548 
00549 //:
00550 //  This function handles the case where the actual bits per pixel per band
00551 //  is less then the actual bpppb AND where the data is vcl_left justified.  This
00552 //  shifts the data so that it it vcl_right justified.
00553 //  As of now, this function is untests as I don't have any vcl_left justified data
00554 //  (the NITF spec discourages using it -- probably because it is such a PITA)
00555 template< class T >
00556 void right_justify(T* data, unsigned int num_samples, unsigned int bitsToMove)
00557 {
00558   for (unsigned int i = 0 ; i < num_samples ; i++) {
00559     data[i] = data[i] >> bitsToMove;
00560   }
00561 }
00562 
00563 //don't do anything for bool, float and double (bit shifting isn't allowed)
00564 template<> void right_justify<bool>(bool* /* data */, unsigned int /* num_samples */, unsigned int /* bitsToMove */) {}
00565 template<> void right_justify<float>(float* /* data */, unsigned int /* num_samples */, unsigned int /* bitsToMove */) {}
00566 template<> void right_justify<double>(double* /* data */, unsigned int /* num_samples */, unsigned int /* bitsToMove */) {}
00567 template<> void right_justify< vcl_complex< float > >(vcl_complex< float >* /*data*/, unsigned int /*num_samples*/,
00568                                                       unsigned int /* bitsToMove */) {}
00569 
00570 template< class T >
00571 unsigned int get_index(T in_val)
00572 { return (T)in_val; }
00573 
00574 template<> unsigned int get_index<bool>(bool in_val)
00575 { return in_val ? 1 : 0; }
00576 
00577 template< class T >
00578 vil_image_view_base_sptr get_block_vcl_internal(vil_pixel_format pix_format, vil_memory_chunk_sptr image_memory,
00579                                                 unsigned int pixels_per_block_x, unsigned int pixels_per_block_y,
00580                                                 unsigned int nplanes,
00581                                                 unsigned int i_step, unsigned int j_step, unsigned int plane_step,
00582                                                 bool need_to_right_justify,
00583                                                 unsigned int extra_bits, unsigned int bits_per_pixel_per_band,
00584                                                 bool data_is_all_blank, const vil_nitf2_image_subheader* /*image_header*/, T dummy)
00585 {
00586   //may have to byte align data (only valid for integer type data)
00587   unsigned int num_samples = pixels_per_block_x * pixels_per_block_y * nplanes; //all bands of image
00588 
00589   if (data_is_all_blank) {
00590     //this entire block is blank
00591     T* data_ptr = reinterpret_cast<T*>(image_memory->data());
00592     for (unsigned int i = 0 ;
00593          i < pixels_per_block_x * pixels_per_block_y * nplanes ;
00594          i++)
00595     {
00596       data_ptr[i] = (T)0;
00597     }
00598   } else {
00599     //in the rare case the the actual number of bits per pixel value (ABPP) is less than the number of bits
00600     //used in the data (NBPP) AND the data is vcl_left justified... then we correct that here
00601     if (need_to_right_justify)
00602       right_justify<T>(static_cast<T*>(image_memory->data()), image_memory->size()/sizeof(T), extra_bits);
00603     //Nitf files store data in big endian... little endian machines need to convert
00604     vil_nitf2_data_mask_table::maybe_endian_swap(static_cast< char* >(image_memory->data()), image_memory->size(), pix_format);
00605     //if the data is not byte aligned (ie. the actual bits per pixel per band is not divisible
00606     //by 8),then we need to correct that
00607     image_memory = maybe_byte_align_data(image_memory, num_samples, bits_per_pixel_per_band, dummy);
00608   }
00609 
00610   vil_image_view< T >* result =
00611     new vil_image_view< T > (image_memory, reinterpret_cast<T*>(image_memory->data()),
00612                               pixels_per_block_x, pixels_per_block_y, nplanes, i_step, j_step, plane_step);
00613 
00614   return result;
00615 }
00616 
00617 vil_image_view_base_sptr vil_nitf2_image::get_block_j2k( unsigned int blockIndexX, unsigned int blockIndexY ) const
00618 {
00619   if ( ! is_jpeg_2000_compressed() ) return 0;
00620   if ( blockIndexX >= n_block_i() ) return 0;
00621   if ( blockIndexY >= n_block_j() ) return 0;
00622 
00623   //sometimes blocks don't align nicely with the image edge.  I'm not sure
00624   //if this is a bug in the file or if we need to handle it.  Anyway,
00625   //we handle it by using vcl_min.  test file named p0_11xa,ntf exhibits
00626   //this issue
00627   unsigned int i0 = vcl_min( blockIndexX * size_block_i(), ni() );
00628   unsigned int num_i = vcl_min( size_block_i(), ni() - i0 );
00629   unsigned int j0 = vcl_min( blockIndexY * size_block_j(), nj() );
00630   unsigned int num_j = vcl_min( size_block_j(), nj() - j0 );
00631   return get_copy_view( i0, num_i, j0, num_j );
00632 }
00633 
00634 vil_image_view_base_sptr vil_nitf2_image::get_block(unsigned int block_index_x, unsigned int block_index_y) const
00635 {
00636   if (pixel_format() == VIL_PIXEL_FORMAT_UNKNOWN) return 0;
00637 
00638   if ( is_jpeg_2000_compressed() ) {
00639     return get_block_j2k( block_index_x, block_index_y );
00640   }
00641 
00642   vcl_string image_mode_type;
00643   if (!current_image_header()->get_property("IMODE", image_mode_type)) return 0;
00644 
00645   //calculate the start position of the block that we need
00646   int bits_per_pixel_per_band, actualBitsPerPixelPerBand;
00647   vcl_string bitJustification;
00648   if (!current_image_header()->get_property("NBPP", bits_per_pixel_per_band) ||
00649       !current_image_header()->get_property("ABPP", actualBitsPerPixelPerBand) ||
00650       !current_image_header()->get_property("PJUST", bitJustification)) {
00651     return 0;
00652   }
00653   int extra_bits = bits_per_pixel_per_band - actualBitsPerPixelPerBand;
00654   bool need_to_right_justify = bitJustification == "L" && (extra_bits > 0);
00655 
00656   //bytes per pixel... round up to nearest byte
00657   //unsigned int bytesPerPixelPerBand = bits_per_pixel_per_band / 8;
00658   //if (bits_per_pixel_per_band % 8 != 0) bytesPerPixelPerBand++;
00659 
00660   unsigned int pixels_per_block = size_block_i() * size_block_j();
00661   unsigned int bits_per_band = pixels_per_block * bits_per_pixel_per_band;
00662   unsigned int bytes_per_block_per_band = bits_per_band / 8;
00663   if (bits_per_band % 8 != 0) bytes_per_block_per_band++;     //round up if remainder vcl_left over
00664   unsigned int block_size_bytes = bytes_per_block_per_band * nplanes();
00665   //allocate the memory that we need
00666   vil_memory_chunk_sptr image_memory = new vil_memory_chunk(block_size_bytes, pixel_format());
00667 
00668 
00669   unsigned int i_step(0), j_step(0), plane_step(0);
00670   bool data_is_all_blank = false;
00671   if (image_mode_type == "S") {
00672 #if 0 // NOT USED
00673     unsigned int bytes_per_band = ni() * nj() * bits_per_pixel_per_band / 8;
00674     unsigned int offset_to_desired_block = bytes_per_block_per_band * (block_index_y * n_block_i() + block_index_x);
00675 #endif // 0
00676     //blocks are not contiguous... we'll have to do one read for each band
00677     for (unsigned int i = 0 ; i < nplanes() ; i++) {
00678       vil_streampos current_offset = get_offset_to_image_data_block_band(m_current_image_index, block_index_x, block_index_y, i);
00679       if (current_offset == 0) {
00680         //this block isn't in the stream (ie. it's all blank)... just blank out the memory
00681         data_is_all_blank = true;
00682       } else {
00683         m_stream->seek(current_offset);
00684         char* position_to_read_to = static_cast<char*>(image_memory->data());
00685         position_to_read_to += i*bytes_per_block_per_band;
00686         if (m_stream->read((void*)position_to_read_to, bytes_per_block_per_band) != static_cast<int>(bytes_per_block_per_band)) {
00687           return 0;
00688         }
00689       }
00690     }
00691     i_step = 1;
00692     j_step = size_block_i();
00693     plane_step = size_block_i() * size_block_j();
00694   } else {
00695     //calculate the offset we need
00696     vil_streampos current_offset = get_offset_to_image_data_block_band(m_current_image_index, block_index_x, block_index_y, 0);
00697     if (current_offset == 0) {
00698       //this block isn't in the stream (ie. it's all blank)... just blank out the memory
00699       data_is_all_blank = true;
00700     } else {
00701       //seek to the correct position in the stream
00702       m_stream->seek(current_offset);
00703       //read in the data
00704       if (m_stream->read(image_memory->data(), block_size_bytes) != static_cast<int>(block_size_bytes)) {
00705         return 0;
00706       }
00707     }
00708 
00709     //figure out the layout of the data in the memory chunk we just read in
00710     if (image_mode_type == "B") {
00711       //band interleaved by Block
00712       i_step = 1;
00713       j_step = size_block_i();
00714       plane_step = size_block_i() * size_block_j();
00715     } else if (image_mode_type == "P") {
00716       //band interleaved by Pixel
00717       i_step = nplanes();
00718       j_step = nplanes() * size_block_i();
00719       plane_step = 1;
00720     } else if (image_mode_type == "R") {
00721       //band interleaved by Row
00722       i_step = 1;
00723       j_step = nplanes() * size_block_i();
00724       plane_step = size_block_i();
00725     }
00726   }
00727 
00728   //create image view of the data
00729   vil_image_view_base_sptr view = 0;
00730   switch (vil_pixel_format_component_format(image_memory->pixel_format()))
00731   {
00732 #define GET_BLOCK_CASE(FORMAT, T)\
00733    case FORMAT:{ \
00734     T t= (T)0; \
00735     return get_block_vcl_internal(\
00736        FORMAT, image_memory, size_block_i(),size_block_j(), nplanes(),\
00737        i_step, j_step, plane_step, need_to_right_justify, extra_bits, bits_per_pixel_per_band,\
00738        data_is_all_blank, current_image_header(), t);\
00739    } break
00740 
00741     GET_BLOCK_CASE(VIL_PIXEL_FORMAT_BYTE, vxl_byte);
00742     GET_BLOCK_CASE(VIL_PIXEL_FORMAT_SBYTE, vxl_sbyte);
00743 
00744 #if VXL_HAS_INT_64
00745     GET_BLOCK_CASE(VIL_PIXEL_FORMAT_UINT_64, vxl_uint_64);
00746     GET_BLOCK_CASE(VIL_PIXEL_FORMAT_INT_64, vxl_int_64);
00747 #endif
00748     GET_BLOCK_CASE(VIL_PIXEL_FORMAT_UINT_32, vxl_uint_32);
00749     GET_BLOCK_CASE(VIL_PIXEL_FORMAT_INT_32, vxl_int_32);
00750     GET_BLOCK_CASE(VIL_PIXEL_FORMAT_UINT_16, vxl_uint_16);
00751     GET_BLOCK_CASE(VIL_PIXEL_FORMAT_INT_16, vxl_int_16);
00752     GET_BLOCK_CASE(VIL_PIXEL_FORMAT_BOOL, bool);
00753     GET_BLOCK_CASE(VIL_PIXEL_FORMAT_FLOAT, float);
00754     GET_BLOCK_CASE(VIL_PIXEL_FORMAT_DOUBLE, double);
00755     GET_BLOCK_CASE(VIL_PIXEL_FORMAT_COMPLEX_FLOAT, vcl_complex<float>);
00756 #undef GET_BLOCK_CASE
00757 
00758    default:
00759     assert(!"Unknown vil data type.");
00760     break;
00761   }
00762   return view;
00763 }
00764 
00765 template<> bool* byte_align_data<bool>(bool* in_data, unsigned int num_samples, unsigned int in_bits_per_sample, bool* out_data)
00766 {
00767   switch (sizeof(bool))
00768   {
00769    case 1:
00770     byte_align_data((vxl_byte*)in_data, num_samples, in_bits_per_sample, (vxl_byte*)out_data);
00771     break;
00772    case 2:
00773     byte_align_data((vxl_uint_16*)in_data, num_samples, in_bits_per_sample, (vxl_uint_16*)out_data);
00774     break;
00775    case 4:
00776     byte_align_data((vxl_uint_32*)in_data, num_samples, in_bits_per_sample, (vxl_uint_32*)out_data);
00777     break;
00778 #if VXL_HAS_INT_64
00779    case 8:
00780     byte_align_data((vxl_uint_64*)in_data, num_samples, in_bits_per_sample, (vxl_uint_64*)out_data);
00781     break;
00782 #endif //VXL_HAS_INT_64
00783    default:
00784     assert(!"Unsupported size of bool.");
00785   }
00786 
00787 #if 0
00788   //dignostic info
00789   vcl_cout << "\nBools: ";
00790   for (unsigned int i = 0 ; i < num_samples ; i++) {
00791     vcl_cout << (out_data[i] ?  '1' : '0');
00792   }
00793   vcl_cout << vcl_endl;
00794 #endif //0
00795   return out_data;
00796 }
00797 
00798 bool vil_nitf2_image::get_property (char const *tag, void *property_value) const
00799 {
00800   if (vcl_strcmp(vil_property_size_block_i, tag)==0)
00801   {
00802     if (property_value)
00803       *static_cast<unsigned*>(property_value) = this->size_block_i();
00804     return true;
00805   }
00806 
00807   if (vcl_strcmp(vil_property_size_block_j, tag)==0)
00808   {
00809     if (property_value)
00810       *static_cast<unsigned*>(property_value) = this->size_block_j();
00811     return true;
00812   }
00813   vcl_string result;
00814   if (m_file_header.get_property(tag, result) ||
00815       (current_image_header() && current_image_header()->get_property(tag, result)))
00816   {
00817     property_value = vcl_malloc(result.size());
00818     vcl_memcpy(property_value, result.c_str(), result.size());
00819     return true;
00820   }
00821   return false;
00822  }
00823 
00824 vil_nitf2_field::field_tree* vil_nitf2_image::get_tree( ) const
00825 {
00826   vil_nitf2_field::field_tree* t = new vil_nitf2_field::field_tree;
00827   t->columns.push_back( "NITF File" );
00828   t->children.push_back( get_header().get_tree() );
00829   unsigned int i;
00830   for ( i = 0 ; i < m_image_headers.size() ; i++ ){
00831     t->children.push_back( m_image_headers[i]->get_tree(i+1) );
00832   }
00833   for ( i = 0 ; i < m_des.size() ; i++ ){
00834     t->children.push_back( m_des[i]->get_tree(i+1) );
00835   }
00836   return t;
00837 }
00838 

Generated on Sat Nov 22 05:07:52 2008 for core/vil by  doxygen 1.5.1