OSSIM - Open Source Software Image Map  Version 1.9.0 (20180803)
ossimKakaduNitfReader.cpp
Go to the documentation of this file.
1 //---
2 //
3 // License: MIT
4 //
5 // Author: David Burken
6 //
7 // Description:
8 //
9 // Class definition for reader of NITF images with JPEG2000 (J2K) compressed
10 // blocks using kakadu library for decompression. The image data segment
11 // can be raw J2K or have a JP2 wrapper.
12 //
13 //---
14 // $Id$
15 
16 #include "ossimKakaduNitfReader.h"
17 #include "ossimKakaduCommon.h"
18 #include "ossimKakaduMessaging.h"
19 
20 #include <ossim/base/ossimCommon.h>
22 #include <ossim/base/ossimNotify.h>
25 #include <ossim/base/ossimTrace.h>
26 
29 
35 
36 #include <jp2.h>
37 #include <kdu_sample_processing.h>
38 #include <kdu_region_decompressor.h>
39 
40 #include <iostream>
41 
42 using namespace kdu_core;
43 using namespace kdu_supp;
44 
45 #ifdef OSSIM_ID_ENABLED
46 static const char OSSIM_ID[] = "$Id";
47 #endif
48 
49 static const ossimTrace traceDebug( ossimString("ossimKakaduNitfReader:debug") );
50 static const ossimTrace traceDump( ossimString("ossimKakaduNitfReader:dump") );
51 
53  "ossimKakaduNitfReader",
55 
58  m_startOfCodestreamOffset(0),
59  m_jp2FamilySrc(0),
60  m_jp2Source(0),
61  m_channels(0),
62  m_codestream(),
63  m_threadEnv(0),
64  m_openTileThreadQueue(0),
65  m_sourcePrecisionBits(0),
66  m_minDwtLevels(0),
67  m_imageDims(0),
68  m_minSampleValue(ossim::nan()),
69  m_maxSampleValue(ossim::nan()),
70  m_nullSampleValue(ossim::nan())
71 {
72  kdu_customize_warnings(&pretty_cout); // Deliver warnings to stdout.
73  kdu_customize_errors(&pretty_cerr); // Deliver errors to stderr + throw exc
74 }
75 
77 {
78  // Kakadu kdu_thread_entity::terminate throws exceptions...
79  try
80  {
81  // Cleanup processing environment
82  if ( m_threadEnv )
83  {
84  m_threadEnv->terminate(m_openTileThreadQueue, true);
85 
86  // Terminates background codestream processing.
87  m_threadEnv->cs_terminate(m_codestream);
88 
89  m_threadEnv->destroy();
90  delete m_threadEnv;
91  m_threadEnv = 0;
92  }
93 
94  if ( m_codestream.exists() )
95  {
96  m_codestream.destroy();
97  }
98 
100  {
102  }
103  if ( m_jp2Source )
104  {
105  delete m_jp2Source;
106  m_jp2Source = 0;
107  }
108  if ( m_jp2FamilySrc )
109  {
110  delete m_jp2FamilySrc;
111  m_jp2FamilySrc = 0;
112  }
113  if ( m_channels )
114  {
115  m_channels->clear();
116  delete m_channels;
117  m_channels = 0;
118  }
119  }
120  catch ( kdu_core::kdu_exception exc )
121  {
122  // kdu_exception is an int typedef.
123  if ( m_threadEnv != 0 )
124  {
125  m_threadEnv->handle_exception(exc);
126  }
127  ostringstream e;
128  e << "ossimKakaduNitfReader::~ossimKakaduNitfReader\n"
129  << "Caught exception from kdu_region_decompressor: " << exc << "\n";
130  ossimNotify(ossimNotifyLevel_WARN) << e.str() << std::endl;
131  }
132  catch ( std::bad_alloc& )
133  {
134  if ( m_threadEnv != 0 )
135  {
136  m_threadEnv->handle_exception(KDU_MEMORY_EXCEPTION);
137  }
138  std::string e =
139  "Caught exception from kdu_region_decompressor: std::bad_alloc";
140  ossimNotify(ossimNotifyLevel_WARN) << e << std::endl;
141  }
142  catch( ... )
143  {
144  std::string e =
145  "Caught unhandled exception from kdu_region_decompressor";
146  ossimNotify(ossimNotifyLevel_WARN) << e << std::endl;
147  }
148 
150 }
151 
153 {
154  return ossimString("ossim_kakadu_nitf_reader");
155 }
156 
158 {
159  return ossimString("ossim kakadu nitf reader");
160 }
161 
163 {
164  ossim_uint32 result = 1; // Add r0
165  if ( isEntryJ2k() )
166  {
167  if (m_minDwtLevels)
168  {
169  //---
170  // Add internal overviews.
171  //---
172  result += m_minDwtLevels;
173  }
174 
175  if (theOverview.valid())
176  {
178  }
179  }
180  else
181  {
183  }
184  return result;
185 }
186 
188  ossim_uint32 resLevel) const
189 {
190  ossim_uint32 result = 0;
191  if ( isEntryJ2k() )
192  {
193  if ( isValidRLevel(resLevel) )
194  {
195  ossim_uint32 level = resLevel;
196 
197  if (theStartingResLevel) // This is an overview.
198  {
199  //---
200  // Adjust the level to be relative to the reader using this as
201  // overview.
202  //---
203  level = resLevel - theStartingResLevel;
204  }
205 
206  if (level <= m_minDwtLevels)
207  {
208  result = m_imageDims[level].height();
209  }
210  else if ( theOverview.valid() )
211  {
212  // Note the non-adjusted resLevel is passed to this by design.
213  result = theOverview->getNumberOfLines(resLevel);
214  }
215  }
216  }
217  else // Not our entry.
218  {
219  result = ossimNitfTileSource::getNumberOfLines(resLevel);
220  }
221  return result;
222 }
223 
225  ossim_uint32 resLevel) const
226 {
227  ossim_uint32 result = 0;
228  if ( isEntryJ2k() )
229  {
230  if ( isValidRLevel(resLevel) )
231  {
232  ossim_uint32 level = resLevel;
233 
234  if (theStartingResLevel) // This is an overview.
235  {
236  //---
237  // Adjust the level to be relative to the reader using this as
238  // overview.
239  //---
240  level = resLevel - theStartingResLevel;
241  }
242 
243  if (level <= m_minDwtLevels)
244  {
245  result = m_imageDims[level].width();
246  }
247  else if ( theOverview.valid() )
248  {
249  // Note the non-adjusted resLevel is passed to this by design.
250  result = theOverview->getNumberOfSamples(resLevel);
251  }
252  }
253  }
254  else // Not our entry.
255  {
256  result = ossimNitfTileSource::getNumberOfSamples(resLevel);
257  }
258  return result;
259 }
260 
262  const ossim_float64& pix)
263 {
264  //---
265  // Store and call base ossimImageHandler::setMinPixelValue in case someone
266  // does a save state on the ossimImageHandler::theMetaData.
267  //---
268  m_minSampleValue = pix;
270  if ( theTile.valid() )
271  {
272  theTile->setMinPix(pix, band);
273  }
274  if ( theCacheTile.valid() )
275  {
276  theCacheTile->setMinPix(pix, band);
277  }
278 }
279 
281  const ossim_float64& pix)
282 {
283  //---
284  // Store and call base ossimImageHandler::setMaxPixelValue in case someone
285  // does a save state on the ossimImageHandler::theMetaData.
286  //---
287  m_maxSampleValue = pix;
289  if ( theTile.valid() )
290  {
291  theTile->setMaxPix(pix, band);
292  }
293  if ( theCacheTile.valid() )
294  {
295  theCacheTile->setMaxPix(pix, band);
296  }
297 }
298 
300  const ossim_float64& pix)
301 {
302  //---
303  // NOTES:
304  //
305  // 1) If the null pixel value has changed a makeBlank must be performed or the validate
306  // method will not work correctly.
307  //
308  // 2) Must set the tile status to unknown prior to the makeBlank or it won't
309  // do anything.
310  //
311  // 3) It would be nice to do this after all the calls to setNullPixelValue are finished
312  // with a dirty flag or something. In reality though the makeBlank will only be called
313  // once as this only happens(usually) with elevation data which is one band.
314  //---
315 
316  //---
317  // Store and call base ossimImageHandler::setNullPixelValue in case someone
318  // does a save state on the ossimImageHandler::theMetaData.
319  //---
320  m_nullSampleValue = pix;
322  if ( theTile.valid() )
323  {
324  if ( theTile->getNullPix(band) != pix )
325  {
326  theTile->setNullPix(pix, band);
328  theTile->makeBlank();
329  }
330  }
331  if ( theCacheTile.valid() )
332  {
333  if ( theCacheTile->getNullPix(band) != pix )
334  {
335  theCacheTile->setNullPix(pix, band);
338  }
339  }
340 }
341 
343 {
345  {
347  }
348  return m_minSampleValue;
349 }
350 
352 {
354  {
356  }
357  return m_maxSampleValue;
358 }
359 
361 {
363  {
365  }
366  return m_nullSampleValue;
367 }
368 
370  ossimImageData* result)
371 {
372  bool status = false;
373 
374  // static bool traced = false;
375 
376  // Must be j2k entry, not past number of levels, bands must match.
377  if ( isEntryJ2k() )
378  {
379  if ( isValidRLevel(resLevel) && result &&
380  (result->getNumberOfBands() == getNumberOfOutputBands()) )
381  {
382  ossim_uint32 level = resLevel - theStartingResLevel;
383 
384 #if 0 /* please leave for debug */
385  cout << "ovr get tile res level: " << resLevel
386  << " start level: " << theStartingResLevel
387  << "\nlevel: " << level
388  << "\nrect3: " << result->getImageRectangle() << endl;
389 #endif
390 
391  if (level <= m_minDwtLevels)
392  {
393  // Internal overviews...
394  try
395  {
396  if ( m_channels )
397  {
399  m_codestream,
400  static_cast<int>(level),
401  m_threadEnv,
403  result);
404  }
405  else
406  {
408  static_cast<int>(level),
409  m_threadEnv,
411  result);
412  }
413  }
414  catch(const ossimException& e)
415  {
417  << __FILE__ << ":" << __LINE__ << " caught exception\n"
418  << e.what() << std::endl;
419  status = false;
420  }
421 
422  } // matches: if (resLevel <= m_minDwtLevels)
423  else if ( theOverview.valid() )
424  {
425  //---
426  // Note: Passing non-adjusted "resLevel" to get tile by design.
427  //---
428  status = theOverview->getTile(result, resLevel);
429  }
430  }
431  else // Failed range check.
432  {
434  << __FILE__ << " " << __LINE__
435  << "Range error." << std::endl;
436  status = false;
437  }
438 
439  } // matches: if ( isEntryJ2k() )
440  else
441  {
442  // Not our entry, call the base.
443  status = ossimNitfTileSource::getOverviewTile(resLevel, result);
444  }
445 
446  return status;
447 
448 } // End: bool ossimKakaduNitfReader::getOverviewTile( ... )
449 
451 {
452 
453  bool result = true;
454 
455  if ( isEntryJ2k() )
456  {
457  ossimIpt ul(x, y);
458 
459  ossimIpt lr(ul.x + theCacheSize.x - 1,
460  ul.y + theCacheSize.y - 1);
461 
462  // Set the cache rectangle to be an even j2k tile.
464 
465  // Let the getOverviewTile do the rest of the work.
466  if ( getOverviewTile(0, theCacheTile.get()) )
467  {
468  // Add it to the cache for the next time.
470  }
471  else
472  {
474  << __FILE__ << ":" << __LINE__
475  << "\nossimKakaduNitfReader::loadBlock failed!"
476  << std::endl;
477  result = false;
478  }
479  }
480  else
481  {
483  }
484 
485  return result;
486 }
487 
489 {
490  static const char MODULE[] = "ossimKakaduNitfReader::parseFile";
491 
492  if (traceDebug())
493  {
494  ossimNotify(ossimNotifyLevel_DEBUG) << MODULE << " entered...\n";
495  }
496 
497  bool result = ossimNitfTileSource::parseFile();
498 
499  if (result)
500  {
501  //---
502  // Look through the entries to see if any are j2k; if not, set result to
503  // false so the ossimNitfTileSource will pick this file up instead of
504  // ossimKakaduNitfReader.
505  //---
506 
507  result = false; // Must prove we have a j2k entry.
508 
509  for (ossim_uint32 i = 0; i < theNumberOfImages; ++i)
510  {
511  if (theNitfImageHeader[i]->getCompressionCode() == "C8") // j2k
512  {
513  result = true;
514  break;
515  }
516  }
517  }
518 
519  if (traceDebug())
520  {
522  << MODULE << " exit status = " << (result?"true\n":"false\n");
523  }
524 
525  return result;
526 }
527 
529 {
530  static const char MODULE[] = "ossimKakaduNitfReader::allocate";
531 
532  if (traceDebug())
533  {
534  ossimNotify(ossimNotifyLevel_DEBUG) << MODULE << " entered...\n";
535 
536  }
537 
538  bool result = ossimNitfTileSource::allocate();
539 
540  if ( isEntryJ2k() && result )
541  {
542  // This only finds "Start Of Codestream" (SOC) so it's fast.
543  result = scanForJpegBlockOffsets();
544 
545  if (traceDebug())
546  {
548  if( hdr )
549  {
551  << "start_of_data: " << hdr->getDataLocation() << "\n";
552  }
554  << "start_of_codestream: " << m_startOfCodestreamOffset << "\n";
555  }
556 
557  if ( result )
558  {
559  // Kakadu throws exceptions so wrap in try block.
560  try
561  {
562  // Position to start of code stream prior to create call.
563  theFileStr->seekg(m_startOfCodestreamOffset, ios_base::beg);
564 
565  //---
566  // Initialize the codestream. The class ossimKakaduNitfReader is a
567  // kdu_compressed source so we feed ourself to the codestream.
568  //---
569 
570  // Construct multi-threaded processing environment if required.
571  if ( m_threadEnv )
572  {
573  m_threadEnv->terminate(NULL, true);
574  m_threadEnv->cs_terminate(m_codestream);
575  m_threadEnv->destroy();
576  }
577 
578  if( m_codestream.exists() )
579  {
580  m_codestream.destroy();
581  }
582 
583  if ( !m_threadEnv )
584  {
585  m_threadEnv = new kdu_thread_env();
586  }
587 
588  m_threadEnv->create(); // Creates the single "owner" thread
589 
590  // Check for threads in prefs file.
591  ossim_uint32 threads = 1;
592  const char* lookup = ossimPreferences::instance()->findPreference("kakadu_threads");
593  if ( lookup )
594  {
595  threads = ossimString::toUInt32(lookup);
596  if ( threads > 1 )
597  {
598  for (ossim_uint32 nt=1; nt < threads; ++nt)
599  {
600  if ( !m_threadEnv->add_thread() )
601  {
602  if (traceDebug())
603  {
604  ossimNotify(ossimNotifyLevel_WARN) << "Unable to create thread!\n";
605  }
606  }
607  }
608  }
609  }
610 
611  m_openTileThreadQueue = m_threadEnv->add_queue(NULL,NULL,"open_tile_q");
612 
613  if ( checkJp2Signature() )
614  {
615  // Note we must be at the JP2 signature block at this point for the open call.
616  m_jp2FamilySrc = new jp2_family_src();
617  m_jp2FamilySrc->open(this);
618 
619  if (m_jp2FamilySrc->exists())
620  {
621  m_jp2Source = new kdu_supp::jp2_source();
622 
624  m_jp2Source->read_header();
625 
626  if (traceDebug())
627  {
628  jp2_colour colour = m_jp2Source->access_colour();
629  if ( colour.exists() )
630  {
632  << "jp2 color space: " << colour.get_space() << endl;
633  }
634  }
635  }
637  }
638  else
639  {
640  m_codestream.create(this, m_threadEnv);
641  }
642 
643  if ( m_codestream.exists() )
644  {
645  //---
646  // We have to store things here in this non-const method because
647  // NONE of the kakadu methods are const.
648  //---
649  m_minDwtLevels = m_codestream.get_min_dwt_levels();
650 
651  //---
652  // NOTE: ossimNitfTileSource::allocate() calls open overview
653  // before the number of levels is known.
654  // Set the starting res level for the overview now that the levels
655  // are known.
656  //---
657  if ( theOverview.valid() )
658  {
660  }
661 
662  // ASSUMPTION: All bands same bit depth.
663  m_sourcePrecisionBits = m_codestream.get_bit_depth(0, true);
664 
665  m_codestream.set_persistent(); // ????
666  m_codestream.enable_restart(); // ????
667 
668  // Get the image and tile dimensions.
669  std::vector<ossimIrect> tileDims;
671  m_imageDims,
672  tileDims) == false )
673  {
675  << __FILE__ << " " << __LINE__ << " " << MODULE
676  << "Could not ascertain dimensions!" << std::endl;
677  result = false;
678  }
679 
680  kdu_dims region_of_interest;
681  region_of_interest.pos.x = 0;
682  region_of_interest.pos.y = 0;
683  region_of_interest.size.x = m_imageDims[0].width();
684  region_of_interest.size.y = m_imageDims[0].height();
685 
686  m_codestream.apply_input_restrictions(
687  0, // first_component
688  0, // max_components (0 = all remaining will appear)
689  0, // highest resolution level
690  0, // max_layers (0 = all layers retained)
691  &region_of_interest, // expanded out to block boundary.
692  KDU_WANT_OUTPUT_COMPONENTS);
693 
694  // Configure the kdu_channel_mapping if it makes sense.
696 
697  if (traceDebug())
698  {
700  << "m_codestream.get_num_components(false): "
701  << m_codestream.get_num_components(false)
702  << "\nm_codestream.get_num_components(true): "
703  << m_codestream.get_num_components(true)
704  << "\nm_codestream.get_bit_depth(0, true): "
705  << m_codestream.get_bit_depth(0, true)
706  << "\nm_codestream.get_signed(0, true): "
707  << m_codestream.get_signed(0, true)
708  << "\nm_codestream.get_min_dwt_levels(): "
709  << m_codestream.get_min_dwt_levels()
710  << "\ntheNumberOfInputBands: "
712  << "\ntheNumberOfOutputBands: "
714  << "\nthreads: " << threads
715  << "\n";
716  for ( std::vector<ossimIrect>::size_type i = 0; i < m_imageDims.size(); ++i )
717  {
719  << "m_imageDims[" << i << "]: " << m_imageDims[i] << "\n";
720  }
721  }
722  }
723  else // if ( m_codestream.exists() )
724  {
725  result = false;
726  }
727 
728  } // End: try block
729  catch( const ossimException& e )
730  {
731  result = false;
732  if (traceDebug())
733  {
735  << MODULE << " Caught exception: " << e.what() << std::endl;
736  }
737  }
738  catch( ... )
739  {
740  result = false;
741  if (traceDebug())
742  {
744  << MODULE << " Caught unknown exception!" << std::endl;
745  }
746  }
747 
748  } // Matches: if ( result )
749 
750  } // Matches: if ( isEntryJ2k() && result )
751 
752  if (traceDebug())
753  {
755  << MODULE << " exit status = " << (result?"true":"false\n")
756  << std::endl;
757  }
758 
759  return result;
760 
761 } // End: ossimKakaduNitfReader::allocate()
762 
764 {
765  bool result = ossimNitfTileSource::allocateBuffers();
766  if ( result )
767  {
768  //---
769  // The ossimImageHandler::openOverview can set our min, max and null before we
770  // have our tiles allocated.
771  //
772  // Set the min, max, and null in case we're being used as an overview handler
773  // and it is out of sync with the base image. Example is dted null is -32767
774  // not default -32768.
775  //---
776  const ossim_uint32 BANDS = getNumberOfOutputBands();
777  for (ossim_uint32 band = 0; band < BANDS; ++band)
778  {
779  if ( theTile.valid() )
780  {
782  {
784  }
786  {
788  }
790  {
792  }
793  }
794  if ( theCacheTile.valid() )
795  {
797  {
799  }
801  {
803  }
805  {
807  }
808  }
809  }
810  }
811  return result;
812 
813 } // End: ossimKakaduNitfReader::allocateBuffer()
814 
816 {
817  bool result = false;
818  if (hdr)
819  {
820  if (hdr->getCompressionCode() == "C8") // j2k
821  {
822  result = true;
823  }
824  else
825  {
827  }
828  }
829  return result;
830 }
831 
833 {
836  if (hdr)
837  {
838  if (hdr->getCompressionCode() == "C8") // j2k
839  {
840  if ( (hdr->getIMode() == "B") && (hdr->getCompressionCode()== "C8") )
841  {
843  }
844  }
845  else
846  {
848  }
849  }
850 }
851 
853 {
854  bool result = false;
855 
857  if( hdr )
858  {
859  // Capture the start of data. This is start of j2k main header.
861 
862  if ( checkJp2Signature() )
863  {
864  result = true;
865  }
866  else
867  {
868  //---
869  // Kakadu library finds j2k tiles. We only find the "Start Of Codestream"(SOC)
870  // which should be at getDataLocation() but not in all cases.
871  //---
872 
873  // Seek to the first block.
874  theFileStr->seekg(m_startOfCodestreamOffset, ios_base::beg);
875  if ( theFileStr->good() )
876  {
877  //---
878  // Read the first two bytes and test for SOC (Start Of Codestream)
879  // marker.
880  //---
881  ossim_uint8 markerField[2];
882  theFileStr->read( (char*)markerField, 2);
883 
884  if ( (markerField[0] == 0xff) && (markerField[1] == 0x4f) )
885  {
886  result = true;
887  }
888  else
889  {
890  //---
891  // Scan the file from the beginning for SOC. This handles cases
892  // where the data does not fall on "hdr->getDataLocation()".
893  //
894  // Changed for multi-enty nitf where first entry is j2k, second is
895  // uncompressed. Need to test at site. 02 August 2013 (drb)
896  //---
897  // theFileStr->seekg(0, ios_base::beg);
898  theFileStr->seekg(m_startOfCodestreamOffset, ios_base::beg);
899  char c;
900  while ( theFileStr->get(c) )
901  {
902  if (static_cast<ossim_uint8>(c) == 0xff)
903  {
904  if ( theFileStr->get(c) )
905  {
906  if (static_cast<ossim_uint8>(c) == 0x4f)
907  {
910  result = true;
911  break;
912  }
913  }
914  }
915  }
916  }
917 
918  if ( (result == true) && traceDump() )
919  {
921  }
922 
923  } // matches: if (theFileStr->good())
924 
925  } // if ( isJp2() ) ... else {
926 
927  } // matches: if (hdr)
928 
929  return result;
930 
931 } // End: bool ossimKakaduNitfReader::scanForJpegBlockOffsets()
932 
934 {
935  if ( isEntryJ2k() )
936  {
937  // Kakadu library handles.
938  theSwapBytesFlag = false;
939  }
940  else
941  {
943  }
944 }
945 
947 {
948  if ( isEntryJ2k() )
949  {
950  // Always band separate here.
952  }
953  else
954  {
956  }
957 }
958 
960 {
961  bool result = false;
963  if (hdr)
964  {
965  if (hdr->getCompressionCode() == "C8") // j2k
966  {
967  result = true;
968  }
969  }
970  return result;
971 }
972 
974 {
975  bool result = false;
977  if( hdr )
978  {
979  std::streamoff startOfDataPos = hdr->getDataLocation();
980 
981  // Seek to the start of data.
982  theFileStr->seekg(startOfDataPos, ios_base::beg);
983  if ( theFileStr->good() )
984  {
985  const ossim_uint8 J2K_SIGNATURE_BOX[SIGNATURE_BOX_SIZE] =
986  {0x00,0x00,0x00,0x0c,0x6a,0x50,0x20,0x20,0x0d,0x0a,0x87,0x0a};
987 
989 
990  // Read in the box.
991  theFileStr->read((char*)box, SIGNATURE_BOX_SIZE);
992  result = true;
993  for (ossim_uint32 i = 0; i < SIGNATURE_BOX_SIZE; ++i)
994  {
995  if (box[i] != J2K_SIGNATURE_BOX[i])
996  {
997  result = false;
998  break;
999  }
1000  }
1001  }
1002 
1003  // Seek back to the start of data.
1004  theFileStr->seekg(startOfDataPos, ios_base::beg);
1005  }
1006 
1007  return result;
1008 }
1009 
1011 {
1012  bool result = false;
1013 
1014  if ( m_channels )
1015  {
1016  m_channels->clear();
1017  }
1018  else
1019  {
1020  m_channels = new kdu_channel_mapping;
1021  }
1022 
1023  if ( m_jp2Source )
1024  {
1025  // Currently ignoring alpha:
1026  result = m_channels->configure(m_jp2Source, false);
1027  }
1028  else
1029  {
1030  result = m_channels->configure(m_codestream);
1031  }
1032 
1033  if ( result )
1034  {
1035  // If we the mapping doesn't have all our bands we don't use it.
1036  if ( m_channels->get_num_colour_channels() != static_cast<int>(theNumberOfOutputBands) )
1037  {
1038  result = false;
1039  }
1040  }
1041 
1042  if ( !result )
1043  {
1044  m_channels->clear();
1045  delete m_channels;
1046  m_channels = 0;
1047  }
1048 }
1049 
1051 {
1052  //---
1053  // NOTE:
1054  // SOC = 0xff4f Start of Codestream
1055  // SOT = 0xff90 Start of tile
1056  // SOD = 0xff93 Last marker in each tile
1057  // EOC = 0xffd9 End of Codestream
1058  //---
1059 
1061  if(hdr)
1062  {
1063  // Capture the starting position.
1064  std::streampos currentPos = theFileStr->tellg();
1065 
1066  // Seek to the first block.
1067  theFileStr->seekg(m_startOfCodestreamOffset, ios_base::beg);
1068  if (theFileStr->good())
1069  {
1070  out << "offset to codestream: " << m_startOfCodestreamOffset << "\n";
1071 
1072  //---
1073  // Read the first two bytes and test for SOC (Start Of Codestream)
1074  // marker.
1075  //---
1076  ossim_uint8 markerField[2];
1077  theFileStr->read( (char*)markerField, 2);
1078 
1079  bool foundSot = false;
1080  if ( (markerField[0] == 0xff) && (markerField[1] == 0x4f) )
1081  {
1082  // Get the SIZ marker and dump it.
1083  theFileStr->read( (char*)markerField, 2);
1084  if ( (markerField[0] == 0xff) && (markerField[1] == 0x51) )
1085  {
1086  ossimJ2kSizRecord siz;
1087  siz.parseStream( *theFileStr );
1088  siz.print(out);
1089  }
1090 
1091  // Find the firt tile marker.
1092  char c;
1093  while ( theFileStr->get(c) )
1094  {
1095  if (static_cast<ossim_uint8>(c) == 0xff)
1096  {
1097  if ( theFileStr->get(c) )
1098  {
1099  out << "marker: 0xff" << hex << (ossim_uint16)c << dec << endl;
1100 
1101  if (static_cast<ossim_uint8>(c) == 0x52)
1102  {
1103  out << "\nFound COD...\n\n" << endl;
1104  ossimJ2kCodRecord cod;
1105  cod.parseStream( *theFileStr );
1106  cod.print(out);
1107 
1108  }
1109  else if (static_cast<ossim_uint8>(c) == 0x55)
1110  {
1111  out << "\nFound TLM...\n\n" << endl;
1112  ossimJ2kTlmRecord tlm;
1113  tlm.parseStream( *theFileStr );
1114  tlm.print(out);
1115  }
1116  else if (static_cast<ossim_uint8>(c) == 0x90)
1117  {
1118  foundSot = true;
1119  break;
1120  }
1121  }
1122  }
1123  }
1124  }
1125 
1126  if (foundSot) // At SOT marker...
1127  {
1128  const ossim_uint32 BLOCKS =
1130  for (ossim_uint32 i = 0; i < BLOCKS; ++i)
1131  {
1132  std::streamoff pos = theFileStr->tellg();
1133  out << "sot pos: " << pos << endl;
1134  ossimJ2kSotRecord sotRecord;
1135  sotRecord.parseStream( *theFileStr );
1136  pos += sotRecord.thePsot;
1137  sotRecord.print(out);
1138  theFileStr->seekg(pos, ios_base::beg);
1139  }
1140  }
1141  }
1142 
1143  // If the last byte is read, the eofbit must be reset.
1144  if ( theFileStr->eof() )
1145  {
1146  theFileStr->clear();
1147  }
1148 
1149  // Put the stream back to the where it was.
1150  theFileStr->seekg(currentPos);
1151  }
1152 
1153  return out;
1154 }
virtual bool scanForJpegBlockOffsets()
This method simply checks for Start of Codestream (SOC) marker as the Kakadu library handles finding ...
ossim_uint32 x
virtual ossim_uint32 getNumberOfDecimationLevels() const
Returns the number of decimation levels.
kdu_core::kdu_codestream m_codestream
virtual void initializeCacheTileInterLeaveType()
Initializes the data member "theCacheTileInterLeaveType".
virtual void setMaxPixelValue(ossim_uint32 band, const ossim_float64 &pix)
convenience method to set max pixel value.
std::basic_ostringstream< char > ostringstream
Class for char output memory streams.
Definition: ossimIosFwd.h:35
virtual void setNullPixelValue(ossim_uint32 band, const ossim_float64 &pix)
convenience method to set null pixel value.
virtual ossim_uint32 getNumberOfBands() const
virtual ossim_int32 getNumberOfBlocksPerRow() const =0
virtual void setMaxPixelValue(ossim_uint32 band, const ossim_float64 &pix)
convenience method to set max pixel value.
virtual void setImageRectangle(const ossimIrect &rect)
ossim_uint32 theNumberOfInputBands
void parseStream(ossim::istream &in)
Parse method.
virtual void initializeReadMode()
Initializes the data member "theReadMode" from the current entry.
virtual ~ossimKakaduNitfReader()
virtural destructor
ossim_uint32 y
virtual ossimString getIMode() const =0
bool valid() const
Definition: ossimRefPtr.h:75
std::shared_ptr< ossim::istream > theFileStr
virtual ossimString getShortName() const
Returns short name.
std::ostream & print(std::ostream &out, const std::string &prefix=std::string()) const
print method that outputs a key/value type format adding prefix to keys.
virtual ossim_uint32 getNumberOfLines(ossim_uint32 resLevel=0) const =0
Pure virtual, derived classes must implement.
double nan()
Method to return ieee floating point double precision NAN.
Definition: ossimCommon.h:135
std::streamoff m_startOfCodestreamOffset
This code was derived from https://gist.github.com/mshockwave.
Definition: Barrier.h:8
void parseStream(std::istream &in)
Parse method.
virtual ossim_uint32 getNumberOfLines(ossim_uint32 resLevel=0) const
Returns the number of lines in the image.
virtual void initializeSwapBytesFlag()
Initializes the data member "theSwapBytesFlag" from the current entry.
ossim_uint32 toUInt32() const
unsigned short ossim_uint16
virtual ossim_uint32 getNumberOfSamples(ossim_uint32 resLevel=0) const
Returns the number of samples in the image.
ossimInterleaveType theCacheTileInterLeaveType
virtual ossim_float64 getNullPixelValue(ossim_uint32 band=0) const
IMODE = B, IC = C3 "JPEG compressed blocks".
virtual bool canUncompress(const ossimNitfImageHeader *hdr) const
void configureChannelMapping()
Initializes m_channels to be used with copyRegionToTile if it makes sense.
static ossimAppFixedTileCache * instance(ossim_uint32 maxSize=0)
virtual ossim_uint32 getNumberOfLines(ossim_uint32 resLevel=0) const
Gets number of lines for res level.
std::ostream & dumpTiles(std::ostream &out)
Method to print out tile info.
virtual bool allocate()
Allocates everything for current entry.
virtual ossim_uint32 getNumberOfDecimationLevels() const
This returns the total number of decimation levels.
virtual bool isValidRLevel(ossim_uint32 resLevel) const
Determines if the passed in reslution level is valid.
virtual double getMinPixelValue(ossim_uint32 band=0) const
Retuns the min pixel value.
double ossim_float64
kdu_supp::jp2_source * m_jp2Source
ossim_float64 m_minSampleValue
min/max/null These are class attributes so that when behaving as an overview the owner or base image ...
virtual void setNullPix(ossim_float64 null_pix)
virtual bool getOverviewTile(ossim_uint32 resLevel, ossimImageData *result)
Method to get an overview tile.
ossim_uint32 theNumberOfImages
const char * findPreference(const char *key) const
kdu_supp::kdu_channel_mapping * m_channels
virtual const char * what() const
Returns the error message.
void parseStream(ossim::istream &in)
Parse method.
virtual ossim_float64 getMaxPixelValue(ossim_uint32 band=0) const
unsigned int ossim_uint32
virtual bool allocateBuffers()
Allocates buffers for current entry.
virtual const ossim_float64 * getNullPix() const
virtual void close()
Closes file and destroys all memory allocated.
ossim_uint32 thePsot
The length in bytes of this record including the SOT marker.
std::ostream & print(std::ostream &out, const std::string &prefix=std::string()) const
print method that outputs a key/value type format adding prefix to keys.
virtual void initializeSwapBytesFlag()
Sets the "theSwapBytesFlag" from the current entry.
ossimRefPtr< ossimImageData > theCacheTile
virtual ossimIrect getImageRectangle() const
virtual bool parseFile()
Parses "theImageFile" and initializes all nitf headers.
virtual void setMinPixelValue(ossim_uint32 band, const ossim_float64 &pix)
convenience method to set min pixel value.
virtual bool parseFile()
Parses "theImageFile" and initializes all nitf headers.
kdu_core::kdu_thread_queue * m_openTileThreadQueue
virtual ossim_uint64 getDataLocation() const =0
virtual bool loadBlock(ossim_uint32 x, ossim_uint32 y)
Loads a block of data to theCacheTile.
const ossimNitfImageHeader * getCurrentImageHeader() const
std::ostream & print(std::ostream &out, const std::string &prefix=std::string()) const
print method that outputs a key/value type format adding prefix to keys.
ossimAppFixedTileCache::ossimAppFixedCacheId theCacheId
ossimKakaduNitfReader()
default construtor
static ossimPreferences * instance()
virtual ossim_uint32 getNumberOfSamples(ossim_uint32 resLevel=0) const
Gets the number of samples for res level.
virtual bool getOverviewTile(ossim_uint32 resLevel, ossimImageData *result)
Gets an overview tile.
kdu_supp::jp2_family_src * m_jp2FamilySrc
return status
virtual void makeBlank()
Initializes data to null pixel values.
ossimRefPtr< ossimImageData > theTile
virtual ossimString getCompressionCode() const =0
void setStartingResLevel(ossim_uint32 level)
bool isEntryJ2k() const
Checks current entry image header to see if it is j2k.
ossimRefPtr< ossimImageHandler > theOverview
bool copyRegionToTile(kdu_supp::kdu_channel_mapping *channelMapping, kdu_core::kdu_codestream &codestream, int discard_levels, kdu_core::kdu_thread_env *threadEnv, kdu_core::kdu_thread_queue *threadQueue, ossimImageData *destTile)
Copies region from codestream to tile at a given rlevel.
virtual void setMaxPix(ossim_float64 max_pix)
kdu_core::kdu_thread_env * m_threadEnv
virtual ossimString getLongName() const
Returns long name.
std::ostream & print(std::ostream &out, const std::string &prefix=std::string()) const
print method that outputs a key/value type format adding prefix to keys.
ossim_int32 y
Definition: ossimIpt.h:142
virtual bool canUncompress(const ossimNitfImageHeader *hdr) const
Checks header to see is we can decompress entry.
virtual bool allocate()
Allocates everything for current entry.
virtual void setDataObjectStatus(ossimDataObjectStatus status) const
Full list found in ossimConstants.h.
virtual ossim_uint32 getNumberOfOutputBands() const
virtual ossim_uint32 getNumberOfSamples(ossim_uint32 resLevel=0) const =0
Pure virtual, derived classes must implement.
ossim_int32 x
Definition: ossimIpt.h:141
bool checkJp2Signature()
Checks for jp2 signature block.
virtual ossim_int32 getNumberOfBlocksPerCol() const =0
virtual double getMaxPixelValue(ossim_uint32 band=0) const
Returns the max pixel of the band.
virtual void setNullPixelValue(ossim_uint32 band, const ossim_float64 &pix)
convenience method to set null pixel value.
virtual ossim_float64 getMinPixelValue(ossim_uint32 band=0) const
ossimKakaduNitfReader class for reading NITF images with JPEG2000 (J2K) compressed blocks using kakad...
virtual void initializeReadMode()
Initializes the data member "theReadMode" from the current entry.
RTTI_DEF1_INST(ossimKakaduNitfReader, "ossimKakaduNitfReader", ossimNitfTileSource) ossimKakaduNitfReader
virtual bool loadBlock(ossim_uint32 x, ossim_uint32 y)
Loads a block of data to theCacheTile.
virtual void setMinPix(ossim_float64 min_pix)
virtual bool allocateBuffers()
Allocates buffers for current entry.
virtual double getNullPixelValue(ossim_uint32 band=0) const
Each band has a null pixel associated with it.
virtual void setMinPixelValue(ossim_uint32 band, const ossim_float64 &pix)
convenience method to set min pixel value.
bool getCodestreamDimensions(kdu_core::kdu_codestream &codestream, std::vector< ossimIrect > &imageDims, std::vector< ossimIrect > &tileDims)
Gets image and tile dimensions from codestream for each resolution level (rlevel).
unsigned char ossim_uint8
virtual void initializeCacheTileInterLeaveType()
Initializes the data member "theCacheTileInterLeaveType".
ossimRefPtr< ossimImageData > addTile(ossimAppFixedCacheId cacheId, ossimRefPtr< ossimImageData > data, bool duplicateData=true)
std::vector< ossimRefPtr< ossimNitfImageHeader > > theNitfImageHeader
std::vector< ossimIrect > m_imageDims
Image dimensions for each level.
OSSIMDLLEXPORT std::ostream & ossimNotify(ossimNotifyLevel level=ossimNotifyLevel_WARN)
std::basic_ostream< char > ostream
Base class for char output streams.
Definition: ossimIosFwd.h:23
ossim_uint32 theStartingResLevel
theStartingResLevel If set to something other than zero(default) this is indicative that the reader i...
virtual ossimRefPtr< ossimImageData > getTile(const ossimIpt &origin, ossim_uint32 resLevel=0)
void parseStream(ossim::istream &in)
Parse method.
ossim_uint32 theNumberOfOutputBands
bool isnan(const float &v)
isnan Test for floating point Not A Number (NAN) value.
Definition: ossimCommon.h:91