vil_nitf2_image.cxx
Go to the documentation of this file.
1 // vil_nitf2: Written by Rob Radtke (rob@) and Harry Voorhees (hlv@) of
2 // Stellar Science Ltd. Co. (stellarscience.com) for
3 // Air Force Research Laboratory, 2005.
4 
5 #include <cstring>
6 #include <algorithm>
7 #include <cstdlib>
8 #include "vil_nitf2_image.h"
9 
10 //:
11 // \file
12 
13 #include <cassert>
14 #ifdef _MSC_VER
15 # include <vcl_msvc_warnings.h>
16 #endif
17 #include <vil/vil_stream_fstream.h>
18 #include <vil/vil_image_view.h>
19 #include <vil/vil_property.h>
20 #include <vil/vil_config.h>
22 #include "vil_nitf2_des.h"
23 
24 #if HAS_J2K
25 #include "vil_j2k_image.h"
26 #endif //HAS_J2K
27 
28 int debug_level = 0;
29 
30 //--------------------------------------------------------------------------------
31 // class vil_nitf2_file_format
32 
33 static char const nitf2_string[] = "nitf";
34 
35 char const* vil_nitf2_file_format::tag() const
36 {
37  return nitf2_string;
38 }
39 
41 {
42  auto* im = new vil_nitf2_image( vs );
43  if ( !im->parse_headers() ) {
44  delete im;
45  im = nullptr;
46  }
47  return im;
48 }
49 
52  unsigned /*nx*/,
53  unsigned /*ny*/,
54  unsigned /*nplanes*/,
55  enum vil_pixel_format /*format*/)
56 {
57  //write not supported
58  return nullptr;
59 }
60 
61 //--------------------------------------------------------------------------------
62 // class vil_nitf2_image
63 
66  unsigned int index ) const
67 {
68  vil_streampos p;
70  //there is no data section in the file header and
71  //there is only one
72  assert( por == vil_nitf2_header::enum_subheader );
73  assert( index == 0 );
74  //file header is the first thing
75  p = 0;
76  }
77  else {
78  auto preceding_section = (vil_nitf2_header::section_type)(sec-1);
79  p = get_offset_to( preceding_section, vil_nitf2_header::enum_subheader, 0 ) +
80  size_to( preceding_section, vil_nitf2_header::enum_subheader, -1 ) +
81  size_to( sec, por, index );
82  }
83  return p;
84 }
85 
88  int index ) const
89 {
91  if ( index == -1 ) {
92  int file_header_size;
93  m_file_header.get_property("HL", file_header_size);
94  return (vil_streampos)file_header_size;
95  }
96  else {
97  return 0;
98  }
99  }
100 
101  vil_streampos offset = 0;
102  //if -1 specified, then we want to go past all of them... that is onto the next
103  //section
104  bool going_past_end = false;
105  if ( index == -1 ) {
106  int num_segments;
108  index = num_segments;
109  going_past_end = true;
110  }
111  std::string sh = vil_nitf2_header::section_len_header_tag( sec );
112  std::string s = vil_nitf2_header::section_len_data_tag( sec );
113  int i;
114  for (i = 0 ; i < index ; i++) {
115  int current_header_size;
116  m_file_header.get_property(sh, i, current_header_size);
117  offset += current_header_size;
119  vil_nitf2_long current_data_size;
120  m_file_header.get_property(s, i, current_data_size);
121  offset += current_data_size;
122  }
123  else {
124  int current_data_size;
125  m_file_header.get_property(s, i, current_data_size);
126  offset += current_data_size;
127  }
128  }
129  //we are now at the proper index's subheader... if we need to get to the data
130  //we've got one more jump to do
131  if ( por == vil_nitf2_header::enum_data ) {
132  // if we've skipped past all the segments, then it doesn't make any sense
133  // to skip to the "data" section
134  if ( going_past_end ) { assert(!"skipped past all segments"); return 0L; }
135  int current_header_size;
136  m_file_header.get_property(sh, i, current_header_size);
137  offset += current_header_size;
138  }
139  return offset;
140 }
141 
143 ( vil_stream* vs, unsigned i0, unsigned ni, unsigned j0, unsigned nj, double i_factor, double j_factor ) = nullptr;
144 
146  : m_stream(is),
147  m_current_image_index(0)
148 {
149  m_stream->ref();
150 }
151 
152 vil_nitf2_image::vil_nitf2_image(const std::string& filePath, const char* mode)
153  : m_current_image_index(0)
154 {
155 #ifdef VIL_USE_FSTREAM64
156  m_stream = new vil_stream_fstream64(filePath.c_str(), mode);
157 #else //VIL_USE_FSTREAM64
158  m_stream = new vil_stream_fstream(filePath.c_str(), mode);
159 #endif //VIL_USE_FSTREAM64
160  m_stream->ref();
161 }
162 
164 {
165  for (auto & m_image_header : m_image_headers) {
166  delete m_image_header;
167  }
168  m_image_headers.clear();
169 }
170 
172 {
173  for (auto & m_de : m_des) {
174  delete m_de;
175  }
176  m_des.clear();
177 }
178 
179 
181 {
182  m_stream->unref();
184  clear_des();
185 }
186 
187 unsigned int vil_nitf2_image::current_image() const
188 {
189  return m_current_image_index;
190 }
191 
192 void vil_nitf2_image::set_current_image(unsigned int index)
193 {
194  assert(index < m_image_headers.size());
195  m_current_image_index = index;
196 }
197 
198 unsigned int vil_nitf2_image::nimages() const
199 {
200  int num_images;
201  if (m_file_header.get_property("NUMI", num_images)) return num_images;
202  else return 0;
203 }
204 
206  unsigned int image_index, unsigned int block_index_x,unsigned int block_index_y, int bandIndex) const
207 {
208  //band index is ignored when i_mode != "S"
209  std::string i_mode;
210  current_image_header()->get_property("IMODE", i_mode);
211 
212  //my image header precedes me. Find out the offset to that, then add on the size of
213  //that header... then you have the offset to me (the data)
214  vil_streampos offset =
216 
217  //////////////////////////////////////////////////
218  // now get the position to the desired block/band
219  //////////////////////////////////////////////////
220  int bits_per_pixel_per_band;
221  current_image_header()->get_property("NBPP", bits_per_pixel_per_band);
222 
223 #if 0 //Not valid if blocks are partially filled (JLM 11/03/07)
224  unsigned int bytes_per_band = ni() * nj() * bits_per_pixel_per_band / 8;
225 #endif
226  // New version
227  unsigned int nbi = n_block_i(), nbj = n_block_j();
228  unsigned int sbi = size_block_i(), sbj = size_block_j();
229  unsigned int bytes_per_band = nbi*nbj*sbi*sbj*bits_per_pixel_per_band/8;
230 
231  // What we do here depends on whether we have a data_mask_table or not and
232  // whether i_mode == "S". The most complex case is i_mode != "S" and we have
233  // a dataMask table. In that case, we get some information from the table and
234  // compute some ourselves. Here are all the possible scenarios handled here:
235  // i_mode == "S" and have data_mask_table: just ask data_mask_table for the offset
236  // i_mode == "S" and don't have data_mask_table: compute it ourselves right here
237  // i_mode != "S" and have data_mask_table: ask the data_mask_table for offset to the
238  // block we want; then compute the offset to the band ourselves here
239  // i_mode != "S" and don't have data_mask_table: compute both band and block offset
240  // ourselves here
241  // If it sounds complex, blame the NITF 2.1 spec for that
242  const vil_nitf2_data_mask_table* data_mask_table = current_image_header()->data_mask_table();
243  if (data_mask_table) {
244  offset += data_mask_table->blocked_image_data_offset();
245  }
246  if (data_mask_table && data_mask_table->has_offset_table()) {
247  //have data mask table
248  int bI = i_mode == "S" ? bandIndex : -1;
249  if (data_mask_table->block_band_present(block_index_x, block_index_y, bI))
250  {
251  return 0;
252  }
253  offset += data_mask_table->block_band_offset(block_index_x, block_index_y, bI);
254  }
255  else {
256  unsigned int pixels_per_block = size_block_i() * size_block_j();
257  unsigned int bits_per_band = pixels_per_block * bits_per_pixel_per_band;
258  unsigned int bytes_per_block_per_band = bits_per_band / 8;
259  //round up if remainder left over (this assumes that band/block boundaries
260  //always lie on byte boundaries.
261  if (bits_per_band % 8 != 0) bytes_per_block_per_band++;
262  if (i_mode == "S") {
263  //i_mode == "S" and not have data_mask_table
264  unsigned int offset_to_desired_band = bandIndex * bytes_per_band;
265  unsigned int offset_to_desired_block = bytes_per_block_per_band * (block_index_y * n_block_i() + block_index_x);
266  offset += offset_to_desired_band + offset_to_desired_block;
267  }
268  else {
269  //i_mode != "S" and not have data_mask_table
270  unsigned int block_size_bytes = bytes_per_block_per_band * nplanes();
271  unsigned int offset_to_desired_block = block_size_bytes * (block_index_y * n_block_i() + block_index_x);
272  offset += offset_to_desired_block;
273  }
274  }
275  if (i_mode != "S") {
276  //regardless of whether we had a data_mask_table or not, we've only computed
277  //the offset to the desired block so far. Now, we add on the offset to
278  //the desired band.
279  unsigned int offset_to_desired_band = bandIndex * bytes_per_band;
280  offset += offset_to_desired_band;
281  }
282  return offset;
283 }
284 
286 {
287  if (!m_stream->ok()) return false;
288  //parse file header
289  m_stream->seek(0);
290  if (!m_file_header.read(m_stream)) {
291  return false;
292  }
293  //now parse each image header
295  m_image_headers.resize(nimages());
296  for (unsigned int i = 0 ; i < nimages() ; i++) {
298  m_stream->seek(offset);
300  if (!m_image_headers[i]->read(m_stream)) return false;
301  }
302 
303  //now parse all the DESs (if any)
304  clear_des();
305  int num_des;
306  m_file_header.get_property( "NUMDES", num_des );
307  m_des.resize( num_des );
308  for ( int j = 0 ; j < num_des ; j++ ){
310  m_stream->seek(offset);
311  int data_width;
312  m_file_header.get_property( "LD", j, data_width );
313  m_des[j] = new vil_nitf2_des(file_version(), data_width);
314  if (!m_des[j]->read(m_stream)) return false;
315  }
316  return true;
317 }
318 
320 {
321  return m_file_header.file_version();
322 }
323 
324 char const * vil_nitf2_image::file_format() const
325 {
327  switch (v)
328  {
330  return "unknown";
332  return "nitf10";
334  return "nitf20";
336  return "nitf21";
337  default:
338  return "unknown";
339  }
340 }
341 
343 {
344  assert(m_current_image_index < m_image_headers.size());
346 }
347 
348 unsigned vil_nitf2_image::nplanes() const
349 {
350  return current_image_header()->nplanes();
351 }
352 
353 unsigned vil_nitf2_image::ni() const
354 {
355  //Note that we are choosing to return the number of significant columns
356  //rather than NPPBH*NBPR which would be the total number of pixels in the
357  //image. if NPPBH*NBPR > NCOLS, then all the extra columns are blanked
358  //out pad pixels. Why would anyone want those?
359  int num_significant_cols;
360  if (current_image_header()->get_property("NCOLS", num_significant_cols))
361  {
362  return num_significant_cols;
363  }
364  return 0;
365 }
366 
367 unsigned vil_nitf2_image::nj() const
368 {
369  //Note that we are choosing to return the number of significant rows
370  //rather than NPPBV*NBPC which would be the total number of pixels in the
371  //image. if NPPBV*NBPC > NROWS, then all the extra columns are blanked
372  //out pad pixels. Why would anyone want those?
373  int num_significant_rows;
374  if (current_image_header()->get_property("NROWS", num_significant_rows))
375  {
376  return num_significant_rows;
377  }
378  return 0;
379 }
380 
382 {
383  std::string pixel_type;
384  int bits_per_pixel;
385  if (current_image_header()->get_property("PVTYPE", pixel_type) &&
386  current_image_header()->get_property("NBPP", bits_per_pixel))
387  {
388  //if bits_per_pixel isn't divisible by 8, round up to nearest byte
389  int bytesPerPixel = bits_per_pixel / 8;
390  if (bits_per_pixel % 8 != 0) bytesPerPixel++;
391  bits_per_pixel = bytesPerPixel * 8;
392  if (pixel_type == "INT") {
393  if (bits_per_pixel == 8) {
394  return VIL_PIXEL_FORMAT_BYTE;
395  }
396  else if (bits_per_pixel == 16) {
398  }
399  else if (bits_per_pixel == 32) {
401  }
402 #if VXL_HAS_INT_64
403  else if (bits_per_pixel == 64) {
404  return VIL_PIXEL_FORMAT_UINT_64;
405  }
406 #endif //VXL_HAS_INT_64
407  }
408  else if (pixel_type == "B") {
409  return VIL_PIXEL_FORMAT_BOOL;
410  }
411  else if (pixel_type == "SI") {
412  if (bits_per_pixel == 8) {
413  return VIL_PIXEL_FORMAT_SBYTE;
414  }
415  else if (bits_per_pixel == 16) {
417  }
418  else if (bits_per_pixel == 32) {
420  }
421 #if VXL_HAS_INT_64
422  else if (bits_per_pixel == 64) {
423  return VIL_PIXEL_FORMAT_INT_64;
424  }
425 #endif //VXL_HAS_INT_64
426  }
427  else if (pixel_type == "R") {
428  if (bits_per_pixel == 32) {
429  return VIL_PIXEL_FORMAT_FLOAT;
430  }
431  else if (bits_per_pixel == 64) {
433  }
434  }
435  else if (pixel_type == "C") {
436  //two 32 bit floats (real followed by complex)
437  if (bits_per_pixel == 64) {
439  }// else if (bits_per_pixel == 64) {
440  // return VIL_PIXEL_FORMAT_COMPLEX_DOUBLE;
441  //}
442  }
443  }
445 }
446 
447 unsigned int vil_nitf2_image::size_block_i() const
448 {
450 }
451 
452 unsigned int vil_nitf2_image::size_block_j() const
453 {
455 }
456 
457 unsigned int vil_nitf2_image::n_block_i() const
458 {
460 }
461 
462 unsigned int vil_nitf2_image::n_block_j() const
463 {
465 }
466 
467 void compute_block_and_offset(unsigned j0, unsigned long block_size,
468  unsigned int& block, unsigned int& offset)
469 {
470  block = 0;
471  offset = 0;
472 
473  if (j0 != 0) {
474  block = (j0 / block_size);
475  if (j0 > 0 && j0 % block_size != 0) {
476  offset = j0 - (block * block_size);
477  }
478  }
479 }
480 
482 {
483  std::string compression_type;
484  //ISO/IEC BIFF profile BPJ2k01.00 says that M8 is actually invalid
485  //(ie. you can't use a data mask with jpeg 2000 compression)
486  //not sure why it is an option though
487  return ( current_image_header()->get_property("IC", compression_type) ) &&
488  ( compression_type == "C8" || compression_type == "M8" );
489 }
490 
492  unsigned start_i, unsigned num_i, unsigned start_j, unsigned num_j, double i_factor, double j_factor ) const
493 {
494  // ACCORDING TO DOCUMENTATION, IF PARAMETERS ARE BAD, WE SHOULD RETURN NULL POINTER.
495  if ((start_i + num_i > ni()) || (start_j + num_j > nj())) {
496  return nullptr;
497  }
498  assert( is_jpeg_2000_compressed() );
499  if ( ! s_decode_jpeg_2000 ) {
500 #if HAS_J2K
502 #else //HAS_J2K
503  std::cerr << "Cannot decode JPEG 2000 image. The J2K library was not built." << std::endl;
504  return nullptr;
505 #endif //HAS_J2K
506  }
507 
508  //it is my understanding from BIFF profile BPJ2k01.00 that JPEG compressed files
509  //will only have on image block (ie. it will be clocked within the jp2 codestream),
510  //so we can just pass all the work off to the vil_j2k_image class
512  return s_decode_jpeg_2000( m_stream, start_i, num_i, start_j, num_j, i_factor, j_factor );
513 }
514 
516  unsigned start_j, unsigned num_j) const
517 {
518  // ACCORDING TO DOCUMENTATION, IF PARAMETERS ARE BAD, WE SHOULD RETURN NULL POINTER.
519  if ((start_i + num_i > ni()) || (start_j + num_j > nj())) {
520  return nullptr;
521  }
522 
523  std::string compression_type;
524  if (!current_image_header()->get_property("IC", compression_type)) {
525  return nullptr;
526  }
527 
528  //right now we only plan to support uncompressed and JPEG2000
529  if (compression_type == "NC" || compression_type == "NM") {
530  return get_copy_view_uncompressed(start_i, num_i, start_j, num_j);
531  }
532  else if ( is_jpeg_2000_compressed() ) {
533  return get_copy_view_decimated_j2k( start_i, num_i, start_j, num_j, 1.0, 1.0 );
534  }
535  else {
536  return nullptr;
537  }
538 }
539 
541  unsigned start_j, unsigned num_j) const
542 {
543  return vil_blocked_image_resource::get_copy_view(start_i, num_i, start_j, num_j);
544 }
545 
546 template< class T >
548  unsigned int in_bits_per_sample, T /*dummy*/)
549 {
550  if (in_bits_per_sample != sizeof(T)*8) {
551  vil_memory_chunk_sptr new_memory = new vil_memory_chunk(num_samples*sizeof(T), in_data->pixel_format());
552  byte_align_data((T*)in_data->data(), num_samples, in_bits_per_sample, (T*)new_memory->data());
553  return new_memory;
554  }
555  return in_data;
556 }
557 
558 // don't do anything for float and double (bit shifting isn't allowed)
560  vil_memory_chunk_sptr in_data, unsigned int /* num_samples */, unsigned int /* in_bits_per_sample */, float /*dummy*/)
561 { return in_data; }
562 
564  vil_memory_chunk_sptr in_data, unsigned int /* num_samples */, unsigned int /* in_bits_per_sample */, double /*dummy*/)
565 { return in_data; }
566 
567 template<> vil_memory_chunk_sptr maybe_byte_align_data< std::complex< float > > (
568  vil_memory_chunk_sptr in_data, unsigned int /*num_samples*/, unsigned int /*in_bits_per_sample*/, std::complex<float> /*dummy*/)
569 { return in_data; }
570 
571 
572 //:
573 // This function handles the case where the actual bits per pixel per band
574 // is less then the actual bpppb AND where the data is std::left justified. This
575 // shifts the data so that it is right justified.
576 // As of now, this function is untests as I don't have any std::left justified data
577 // (the NITF spec discourages using it -- probably because it is such a PITA)
578 template< class T >
579 void right_justify(T* data, unsigned int num_samples, unsigned int bitsToMove)
580 {
581  for (unsigned int i = 0 ; i < num_samples ; i++) {
582  data[i] = data[i] >> bitsToMove;
583  }
584 }
585 
586 //don't do anything for bool, float and double (bit shifting isn't allowed)
587 template<> void right_justify<bool>(bool* /* data */, unsigned int /* num_samples */, unsigned int /* bitsToMove */) {}
588 template<> void right_justify<float>(float* /* data */, unsigned int /* num_samples */, unsigned int /* bitsToMove */) {}
589 template<> void right_justify<double>(double* /* data */, unsigned int /* num_samples */, unsigned int /* bitsToMove */) {}
590 template<> void right_justify< std::complex< float > >(std::complex< float >* /*data*/, unsigned int /*num_samples*/,
591  unsigned int /* bitsToMove */) {}
592 
593 template< class T >
594 unsigned int get_index(T in_val)
595 { return (T)in_val; }
596 
597 template<> unsigned int get_index<bool>(bool in_val)
598 { return in_val ? 1 : 0; }
599 
600 template< class T >
602  unsigned int pixels_per_block_x, unsigned int pixels_per_block_y,
603  unsigned int nplanes,
604  unsigned int i_step, unsigned int j_step, unsigned int plane_step,
605  bool need_to_right_justify,
606  unsigned int extra_bits, unsigned int bits_per_pixel_per_band,
607  bool data_is_all_blank, const vil_nitf2_image_subheader* /*image_header*/, T dummy)
608 {
609  //may have to byte align data (only valid for integer type data)
610  unsigned int num_samples = pixels_per_block_x * pixels_per_block_y * nplanes; //all bands of image
611 
612  if (data_is_all_blank) {
613  //this entire block is blank
614  T* data_ptr = reinterpret_cast<T*>(image_memory->data());
615  for (unsigned int i = 0 ;
616  i < pixels_per_block_x * pixels_per_block_y * nplanes ;
617  i++)
618  {
619  data_ptr[i] = (T)0;
620  }
621  }
622  else {
623  //in the rare case where the actual number of bits per pixel value (ABPP) is less than the number of bits
624  //used in the data (NBPP) AND the data is std::left justified... then we correct that here
625  if (need_to_right_justify)
626  right_justify<T>(static_cast<T*>(image_memory->data()), (unsigned int)(image_memory->size()/sizeof(T)), extra_bits);
627  //Nitf files store data in big endian... little endian machines need to convert
628  vil_nitf2_data_mask_table::maybe_endian_swap(static_cast< char* >(image_memory->data()), (unsigned int)(image_memory->size()), pix_format);
629  //if the data is not byte aligned (ie. the actual bits per pixel per band is not divisible
630  //by 8),then we need to correct that
631  image_memory = maybe_byte_align_data(image_memory, num_samples, bits_per_pixel_per_band, dummy);
632  }
633 
634  auto* result =
635  new vil_image_view< T > (image_memory, reinterpret_cast<T*>(image_memory->data()),
636  pixels_per_block_x, pixels_per_block_y, nplanes, i_step, j_step, plane_step);
637 
638  return result;
639 }
640 
641 vil_image_view_base_sptr vil_nitf2_image::get_block_j2k( unsigned int blockIndexX, unsigned int blockIndexY ) const
642 {
643  if ( ! is_jpeg_2000_compressed() ) return nullptr;
644  if ( blockIndexX >= n_block_i() ) return nullptr;
645  if ( blockIndexY >= n_block_j() ) return nullptr;
646 
647  //sometimes blocks don't align nicely with the image edge. I'm not sure
648  //if this is a bug in the file or if we need to handle it. Anyway,
649  //we handle it by using std::min. test file named p0_11xa,ntf exhibits
650  //this issue
651  unsigned int i0 = (std::min)( blockIndexX * size_block_i(), ni() );
652  unsigned int num_i = (std::min)( size_block_i(), ni() - i0 );
653  unsigned int j0 = (std::min)( blockIndexY * size_block_j(), nj() );
654  unsigned int num_j = (std::min)( size_block_j(), nj() - j0 );
655  return get_copy_view( i0, num_i, j0, num_j );
656 }
657 
658 vil_image_view_base_sptr vil_nitf2_image::get_block(unsigned int block_index_x, unsigned int block_index_y) const
659 {
660  if (pixel_format() == VIL_PIXEL_FORMAT_UNKNOWN) return nullptr;
661 
662  if ( is_jpeg_2000_compressed() ) {
663  return get_block_j2k( block_index_x, block_index_y );
664  }
665 
666  std::string image_mode_type;
667  if (!current_image_header()->get_property("IMODE", image_mode_type)) return nullptr;
668 
669  //calculate the start position of the block that we need
670  int bits_per_pixel_per_band, actualBitsPerPixelPerBand;
671  std::string bitJustification;
672  if (!current_image_header()->get_property("NBPP", bits_per_pixel_per_band) ||
673  !current_image_header()->get_property("ABPP", actualBitsPerPixelPerBand) ||
674  !current_image_header()->get_property("PJUST", bitJustification)) {
675  return nullptr;
676  }
677  int extra_bits = bits_per_pixel_per_band - actualBitsPerPixelPerBand;
678  bool need_to_right_justify = bitJustification == "L" && (extra_bits > 0);
679 
680  //bytes per pixel... round up to nearest byte
681  //unsigned int bytesPerPixelPerBand = bits_per_pixel_per_band / 8;
682  //if (bits_per_pixel_per_band % 8 != 0) bytesPerPixelPerBand++;
683 
684  unsigned int pixels_per_block = size_block_i() * size_block_j();
685  unsigned int bits_per_band = pixels_per_block * bits_per_pixel_per_band;
686  unsigned int bytes_per_block_per_band = bits_per_band / 8;
687  if (bits_per_band % 8 != 0) bytes_per_block_per_band++; //round up if remainder std::left over
688  unsigned int block_size_bytes = bytes_per_block_per_band * nplanes();
689  //allocate the memory that we need
690  vil_memory_chunk_sptr image_memory = new vil_memory_chunk(block_size_bytes, pixel_format());
691 
692 
693  unsigned int i_step(0), j_step(0), plane_step(0);
694  bool data_is_all_blank = false;
695  if (image_mode_type == "S") {
696 #if 0 // NOT USED
697  unsigned int bytes_per_band = ni() * nj() * bits_per_pixel_per_band / 8;
698  unsigned int offset_to_desired_block = bytes_per_block_per_band * (block_index_y * n_block_i() + block_index_x);
699 #endif // 0
700  //blocks are not contiguous... we'll have to do one read for each band
701  for (unsigned int i = 0 ; i < nplanes() ; i++) {
702  vil_streampos current_offset = get_offset_to_image_data_block_band(m_current_image_index, block_index_x, block_index_y, i);
703  if (current_offset == 0) {
704  //this block isn't in the stream (ie. it's all blank)... just blank out the memory
705  data_is_all_blank = true;
706  }
707  else {
708  m_stream->seek(current_offset);
709  char* position_to_read_to = static_cast<char*>(image_memory->data());
710  position_to_read_to += i*bytes_per_block_per_band;
711  if (m_stream->read((void*)position_to_read_to, bytes_per_block_per_band) != static_cast<int>(bytes_per_block_per_band)) {
712  return nullptr;
713  }
714  }
715  }
716  i_step = 1;
717  j_step = size_block_i();
718  plane_step = size_block_i() * size_block_j();
719  }
720  else {
721  //calculate the offset we need
722  vil_streampos current_offset = get_offset_to_image_data_block_band(m_current_image_index, block_index_x, block_index_y, 0);
723  if (current_offset == 0) {
724  //this block isn't in the stream (ie. it's all blank)... just blank out the memory
725  data_is_all_blank = true;
726  }
727  else {
728  //seek to the correct position in the stream
729  m_stream->seek(current_offset);
730  //read in the data
731  if (m_stream->read(image_memory->data(), block_size_bytes) != static_cast<int>(block_size_bytes)) {
732  return nullptr;
733  }
734  }
735 
736  //figure out the layout of the data in the memory chunk we just read in
737  if (image_mode_type == "B") {
738  //band interleaved by Block
739  i_step = 1;
740  j_step = size_block_i();
741  plane_step = size_block_i() * size_block_j();
742  }
743  else if (image_mode_type == "P") {
744  //band interleaved by Pixel
745  i_step = nplanes();
746  j_step = nplanes() * size_block_i();
747  plane_step = 1;
748  }
749  else if (image_mode_type == "R") {
750  //band interleaved by Row
751  i_step = 1;
752  j_step = nplanes() * size_block_i();
753  plane_step = size_block_i();
754  }
755  }
756 
757  //create image view of the data
758  vil_image_view_base_sptr view = nullptr;
759  switch (vil_pixel_format_component_format(image_memory->pixel_format()))
760  {
761 #define GET_BLOCK_CASE(FORMAT, T)\
762  case FORMAT:{ \
763  T t= (T)0; \
764  return get_block_vcl_internal(\
765  FORMAT, image_memory, size_block_i(),size_block_j(), nplanes(),\
766  i_step, j_step, plane_step, need_to_right_justify, extra_bits, bits_per_pixel_per_band,\
767  data_is_all_blank, current_image_header(), t);\
768  } break
769 
772 
773 #if VXL_HAS_INT_64
774  GET_BLOCK_CASE(VIL_PIXEL_FORMAT_UINT_64, vxl_uint_64);
775  GET_BLOCK_CASE(VIL_PIXEL_FORMAT_INT_64, vxl_int_64);
776 #endif
784  GET_BLOCK_CASE(VIL_PIXEL_FORMAT_COMPLEX_FLOAT, std::complex<float>);
785 #undef GET_BLOCK_CASE
786 
787  default:
788  assert(!"Unknown vil data type.");
789  break;
790  }
791  return view;
792 }
793 
794 template<> bool* byte_align_data<bool>(bool* in_data, unsigned int num_samples, unsigned int in_bits_per_sample, bool* out_data)
795 {
796  switch (sizeof(bool))
797  {
798  case 1:
799  byte_align_data((vxl_byte*)in_data, num_samples, in_bits_per_sample, (vxl_byte*)out_data);
800  break;
801  case 2:
802  byte_align_data((vxl_uint_16*)in_data, num_samples, in_bits_per_sample, (vxl_uint_16*)out_data);
803  break;
804  case 4:
805  byte_align_data((vxl_uint_32*)in_data, num_samples, in_bits_per_sample, (vxl_uint_32*)out_data);
806  break;
807 #if VXL_HAS_INT_64
808  case 8:
809  byte_align_data((vxl_uint_64*)in_data, num_samples, in_bits_per_sample, (vxl_uint_64*)out_data);
810  break;
811 #endif //VXL_HAS_INT_64
812  default:
813  assert(!"Unsupported size of bool.");
814  }
815 
816 #if 0
817  // diagnostic info
818  std::cout << "\nBools: ";
819  for (unsigned int i = 0 ; i < num_samples ; i++) {
820  std::cout << (out_data[i] ? '1' : '0');
821  }
822  std::cout << std::endl;
823 #endif //0
824  return out_data;
825 }
826 
827 bool vil_nitf2_image::get_property (char const *tag, void *property_value) const
828 {
829  if (std::strcmp(vil_property_size_block_i, tag)==0)
830  {
831  if (property_value)
832  *static_cast<unsigned*>(property_value) = this->size_block_i();
833  return true;
834  }
835 
836  if (std::strcmp(vil_property_size_block_j, tag)==0)
837  {
838  if (property_value)
839  *static_cast<unsigned*>(property_value) = this->size_block_j();
840  return true;
841  }
842  std::string result;
843  if (m_file_header.get_property(tag, result) ||
845  {
846  property_value = std::malloc(result.size());
847  std::memcpy(property_value, result.c_str(), result.size());
848  return true;
849  }
850  return false;
851  }
852 
854 {
855  auto* t = new vil_nitf2_field::field_tree;
856  t->columns.emplace_back("NITF File" );
857  t->children.push_back( get_header().get_tree() );
858  unsigned int i;
859  for ( i = 0 ; i < m_image_headers.size() ; i++ ){
860  t->children.push_back( m_image_headers[i]->get_tree(i+1) );
861  }
862  for ( i = 0 ; i < m_des.size() ; i++ ){
863  t->children.push_back( m_des[i]->get_tree(i+1) );
864  }
865  return t;
866 }
vil_memory_chunk_sptr maybe_byte_align_data(vil_memory_chunk_sptr in_data, unsigned int num_samples, unsigned int in_bits_per_sample, T)
char const * file_format() const override
returns "nitf vM.N".
virtual vil_image_view_base_sptr get_copy_view_decimated_j2k(unsigned i0, unsigned ni, unsigned j0, unsigned nj, double i_factor, double j_factor) const
vil_pixel_format
Describes the type of the concrete data.
vil_pixel_format vil_pixel_format_component_format(enum vil_pixel_format f)
Return the number of components in pixel format f.
vil_smart_ptr< vil_image_view_base > vil_image_view_base_sptr
Definition: vil_fwd.h:18
vxl_int_32 vil_nitf2_long
Definition: vil_nitf2.h:26
bool has_offset_table() const
If this function returns true, then you may call.
std::complex<float> is a scalar for vil's purposes.
~vil_nitf2_image() override
unsigned int get_index< bool >(bool in_val)
vil_stream * m_stream
enum vil_pixel_format pixel_format() const override
Pixel Format.
This class is responsible for parsing a NITF 2.1 data mask table.
unsigned n_block_i() const override
Number of blocks in image width.
vil_image_resource_sptr make_input_image(vil_stream *vs) override
Attempt to make a generic_image which will read from vil_stream vs.
unsigned size_block_i() const override
Block size in columns.
std::vector< std::string > columns
bool get_property(char const *tag, void *property_value=nullptr) const override
Extra property information.
virtual vil_image_view_base_sptr get_copy_view_uncompressed(unsigned i0, unsigned ni, unsigned j0, unsigned nj) const
Concrete view of image data of type T held in memory.
Definition: vil_fwd.h:13
vil_nitf2_image(vil_stream *is)
Instantiate an image resource, but doesn't read anything.
vil_nitf2_classification::file_version file_version() const
vil_j2k: Written by Rob Radtke (rob@) and Harry Voorhees (hlv@) of Stellar Science Ltd.
#define GET_BLOCK_CASE(FORMAT, T)
vxl_uint_32 blocked_image_data_offset() const
std::vector< vil_nitf2_des * > m_des
virtual void seek(vil_streampos position)=0
Goto file pointer.
const vil_nitf2_header & get_header() const
vil_image_resource_sptr make_output_image(vil_stream *vs, unsigned nx, unsigned ny, unsigned nplanes, enum vil_pixel_format) override
Make a "generic_image" on which put_section may be applied.
static vil_image_view_base_sptr(* s_decode_jpeg_2000)(vil_stream *vs, unsigned i0, unsigned ni, unsigned j0, unsigned nj, double i_factor, double j_factor)
All instances of vil_nitf2_image will use s_decode_jpeg_2000() to decode JPEG 2000 streams if you set...
vil_streampos size_to(vil_nitf2_header::section_type sec, vil_nitf2_header::portion_type por, int index) const
virtual vil_streampos read(void *buf, vil_streampos n)=0
Read n bytes into buf. Returns number of bytes read.
A vil_stream implementation using std::fstream.
vil_image_view_base_sptr get_block(unsigned int blockIndexX, unsigned int blockIndexY) const override
virtual void set_current_image(unsigned int index)
Since the VIL API (eg.
char const * tag() const override
Return a character string which uniquely identifies this format.
vil_nitf2_classification::file_version file_version() const
This class is responsible for parsing a NITF 2.1 image header.
const vil_nitf2_data_mask_table * data_mask_table() const
static std::string section_len_data_tag(section_type sec)
unsigned ni() const override
Dimensions: Planes x ni x nj.
static void maybe_endian_swap(char *a, unsigned sizeOfAInBytes, vil_pixel_format pixFormat)
void right_justify< bool >(bool *, unsigned int, unsigned int)
unsigned int get_index(T in_val)
vil_memory_chunk_sptr maybe_byte_align_data< float >(vil_memory_chunk_sptr in_data, unsigned int, unsigned int, float)
vil_streampos get_offset_to(vil_nitf2_header::section_type sec, vil_nitf2_header::portion_type por, unsigned int index=0) const
Stream interface for VIL image loaders.
Definition: vil_stream.h:21
vil_nitf2: Written by Rob Radtke (rob@) and Harry Voorhees (hlv@) of Stellar Science Ltd.
A vil_stream implementation using std::fstream.
#define v
virtual vil_nitf2_field::field_tree * get_tree() const
virtual bool read(vil_stream *stream)
Class for reading NITF 2.1 imagery files.
vil_memory_chunk_sptr maybe_byte_align_data< double >(vil_memory_chunk_sptr in_data, unsigned int, unsigned int, double)
virtual unsigned int current_image() const
unsigned int m_current_image_index
#define vil_property_size_block_i
For unblocked images, the following properties are not implemented.
Definition: vil_property.h:76
vil_streampos get_offset_to_image_data_block_band(unsigned int imageIndex, unsigned int blockIndexX, unsigned int blockIndexY, int bandIndex) const
void right_justify< float >(float *, unsigned int, unsigned int)
unsigned n_block_j() const override
Number of blocks in image height.
void right_justify< double >(double *, unsigned int, unsigned int)
void compute_block_and_offset(unsigned j0, unsigned long block_size, unsigned int &block, unsigned int &offset)
bool is_jpeg_2000_compressed() const
bool * byte_align_data< bool >(bool *in_data, unsigned int num_samples, unsigned int in_bits_per_sample, bool *out_data)
void right_justify(T *data, unsigned int num_samples, unsigned int bitsToMove)
This function handles the case where the actual bits per pixel per band is less then the actual bpppb...
void ref()
up/down the reference count.
Definition: vil_stream.h:45
vil_image_view_base_sptr get_copy_view() const
Create a read/write view of a copy of all the data.
A base class reference-counting view of some image data.
unsigned nplanes() const override
return the image info of the current image.
std::vector< vil_nitf2_image_subheader * > m_image_headers
There is no class or function called vil_property.
Ref. counted block of data on the heap.
vxl_uint_32 block_band_offset(unsigned int block_x, unsigned int block_y, int band=-1) const
if imode == "S", then the band argument is used and I will return the offset to 'band' if imode !...
unsigned int get_pixels_per_block_x() const
void unref()
Definition: vil_stream.cxx:31
vil_nitf2_header m_file_header
virtual bool ok() const =0
Return false if the stream is broken.
int debug_level
#define vil_property_size_block_j
Block size in rows.
Definition: vil_property.h:79
bool get_property(std::string tag, T &out_value) const
Sets out_value to the value of field specified by tag.
T * byte_align_data(T *in_data, unsigned int num_samples, unsigned int in_bits_per_sample, T *out_data)
This function will byte align the data in in_data and store the result in out_data.
vxl_int_32 vil_streampos
Definition: vil_stream.h:16
virtual vil_image_view_base_sptr get_block_j2k(unsigned int blockIndexX, unsigned int blockIndexY) const
static std::string section_len_header_tag(section_type sec)
const vil_nitf2_image_subheader * current_image_header() const
vil_image_view_base_sptr get_block_vcl_internal(vil_pixel_format pix_format, vil_memory_chunk_sptr image_memory, unsigned int pixels_per_block_x, unsigned int pixels_per_block_y, unsigned int nplanes, unsigned int i_step, unsigned int j_step, unsigned int plane_step, bool need_to_right_justify, unsigned int extra_bits, unsigned int bits_per_pixel_per_band, bool data_is_all_blank, const vil_nitf2_image_subheader *, T dummy)
virtual vil_image_view_base_sptr get_copy_view() const
static std::string section_num_tag(section_type sec)
static vil_image_view_base_sptr s_decode_jpeg_2000(vil_stream *vs, unsigned i0, unsigned ni, unsigned j0, unsigned nj, double i_factor, double j_factor)
Static function that can be used to decode a JPEG2000 codestream or file (jp2 file).
vxl_uint_32 block_band_present(unsigned int block_x, unsigned int block_y, int band=-1) const
Returns true iff this block is present in the data. False otherwise.
virtual unsigned int nimages() const
unsigned size_block_j() const override
Block size in rows.
unsigned int get_pixels_per_block_y() const
bool get_property(std::string tag, T &out_value) const
unsigned nj() const override
Dimensions: Planes x ni x nj.