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

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

Generated on Thu Jan 10 14:40:00 2008 for core/vil by  doxygen 1.4.4