OSSIM - Open Source Software Image Map  Version 1.9.0 (20180803)
ossimKakaduJp2Reader.cpp
Go to the documentation of this file.
1 //---
2 //
3 // License: MIT
4 //
5 // Description: Class definition for JPEG2000 JP2 reader.
6 //
7 //---
8 // $Id$
9 
10 #include "ossimKakaduJp2Reader.h"
11 #include "ossimKakaduCommon.h"
12 #include "ossimKakaduMessaging.h"
13 
14 #include <ossim/base/ossimCommon.h>
15 #include <ossim/base/ossimDpt.h>
16 #include <ossim/base/ossimEndian.h>
19 #include <ossim/base/ossimNotify.h>
22 #include <ossim/base/ossimTrace.h>
24 
27 
31 
39 
40 #include <kdu_compressed.h>
41 #include <kdu_elementary.h>
42 #include <kdu_sample_processing.h>
43 #include <kdu_region_decompressor.h>
44 #include <jp2.h>
45 
46 #include <fstream>
47 #include <iostream>
48 #include <string>
49 
50 //---
51 // Kakadu code has defines that have (kdu_uint32) which should be
52 // (kdu_core::kdu_uint32)
53 //---
54 using namespace kdu_core;
55 
56 #ifdef OSSIM_ID_ENABLED
57 static const char OSSIM_ID[] = "$Id";
58 #endif
59 
60 static const ossimTrace traceDebug( ossimString("ossimKakaduJp2Reader:debug") );
61 static const ossimTrace traceDump( ossimString( "ossimKakaduJp2Reader:dump") );
62 
64  "ossimKakaduJp2Reader",
66 
69  theJp2FamilySrc(0),
70  theJp2Source(0),
71  theChannels(0),
72  theCodestream(),
73  theThreadEnv(0),
74  theOpenTileThreadQueue(0),
75  theMinDwtLevels(0),
76  theNumberOfBands(0),
77  theCacheSize(0, 0),
78  theScalarType(OSSIM_SCALAR_UNKNOWN),
79  theImageRect(),
80  theJp2Dims(0),
81  theJp2TileDims(0),
82  theTile(),
83  theCacheTile(),
84  theCacheId(-1)
85 {
86  kdu_customize_warnings(&pretty_cout); // Deliver warnings to stdout.
87  kdu_customize_errors(&pretty_cerr); // Deliver errors to stderr + throw exc
88 }
89 
91 {
92  closeEntry();
93 }
94 
96 {
97  return ossimString("ossim_kakadu_jp2_reader");
98 }
99 
101 {
102  return ossimString("ossim kakadu jp2 reader");
103 }
104 
106 {
107  return ossimString("ossimKakaduJp2Reader");
108 }
109 
111 {
112  ossim_uint32 result = 1; // Add r0
113 
114  if (theMinDwtLevels)
115  {
116  //---
117  // Add internal overviews.
118  //---
119  result += theMinDwtLevels;
120  }
121 
122  if (theOverview.valid())
123  {
124  //---
125  // Add external overviews.
126  //---
128  }
129 
130  return result;
131 }
132 
134  ossim_uint32 resLevel) const
135 {
136  ossim_uint32 result = 0;
137  if ( isValidRLevel(resLevel) )
138  {
139  if (resLevel < theJp2Dims.size() )
140  {
141  result = theJp2Dims[resLevel].height();
142  }
143  else if (theOverview.valid())
144  {
145  result = theOverview->getNumberOfLines(resLevel);
146  }
147  }
148  return result;
149 }
150 
152  ossim_uint32 resLevel) const
153 {
154  ossim_uint32 result = 0;
155  if ( isValidRLevel(resLevel) )
156  {
157  if (resLevel < theJp2Dims.size() )
158  {
159  result = theJp2Dims[resLevel].width();
160  }
161  else if (theOverview.valid())
162  {
163  result = theOverview->getNumberOfSamples(resLevel);
164  }
165  }
166  return result;
167 }
168 
170 {
171  static const char MODULE[] = "ossimKakaduJp2Reader::open";
172 
173  if (traceDebug())
174  {
176  << MODULE << " entered...\n"
177  << "image: " << theImageFile << "\n";
178  }
179 
180  bool result = false;
181 
182  if(isOpen())
183  {
184  closeEntry();
185  }
186 
187  if ( isJp2() )
188  {
189  result = openJp2File();
190 
191  if ( !result )
192  {
193  closeEntry();
194  }
195  }
196 
197  if (traceDebug())
198  {
200  << MODULE << " exit status = " << (result?"true":"false\n")
201  << std::endl;
202  }
203 
204  return result;
205 }
206 
208 {
209  bool result = true;
210 
211  std::ifstream str;
212  str.open(theImageFile.chars(), ios::in | ios::binary);
213 
214  if ( str.is_open() )
215  {
216  const ossim_uint8 J2K_SIGNATURE_BOX[SIGNATURE_BOX_SIZE] =
217  {0x00,0x00,0x00,0x0c,0x6a,0x50,0x20,0x20,0x0d,0x0a,0x87,0x0a};
218 
220 
221  // Read in the box.
222  str.read((char*)box, SIGNATURE_BOX_SIZE);
223 
224  for (ossim_uint32 i = 0; i < SIGNATURE_BOX_SIZE; ++i)
225  {
226  if (box[i] != J2K_SIGNATURE_BOX[i])
227  {
228  result = false;
229  break;
230  }
231  }
232 
233  str.close();
234  }
235  else
236  {
237  result = false;
238 
239  if(traceDebug())
240  {
242  << "isJp2 ERROR:"
243  << "\nCannot open: " << theImageFile.chars() << endl;
244  }
245  }
246 
247  return result;
248 }
249 
251 {
252  static const char MODULE[] = "ossimKakaduJp2Reader::openJp2File";
253 
254  if (traceDebug())
255  {
257  << MODULE << " entered...\n";
258  }
259 
260  bool result = false;
261 
262  theJp2FamilySrc = new kdu_supp::jp2_family_src();
263  theJp2FamilySrc->open(theImageFile.c_str(), true);
264 
265  if (theJp2FamilySrc->exists())
266  {
267  kdu_supp::jp2_source* src = new kdu_supp::jp2_source();
268  theJp2Source = src;
269 
270  src->open(theJp2FamilySrc);
271 
272  src->read_header();
273 
274  if (traceDebug())
275  {
276  kdu_supp::jp2_colour colour = src->access_colour();
277  if ( colour.exists() )
278  {
280  << "jp2 color space: " << colour.get_space() << std::endl;
281  }
282  }
283 
284  theThreadEnv = new kdu_core::kdu_thread_env();
285 
286  theThreadEnv->create(); // Creates the single "owner" thread
287 
288  ossim_uint32 threads = 1;
289 
290  const char* lookup = ossimPreferences::instance()->findPreference("kakadu_threads");
291  if ( lookup )
292  {
293  threads = ossimString::toUInt32(lookup);
294  if ( threads > 1 )
295  {
296  for (ossim_uint32 nt=1; nt < threads; ++nt)
297  {
298  if ( !theThreadEnv->add_thread() )
299  {
300  if (traceDebug())
301  {
303  << "Unable to create thread!\n";
304  }
305  }
306  }
307  }
308  }
309 
311  theThreadEnv->add_queue(NULL,NULL,"open_tile_q");
312 
314 
315  if ( theCodestream.exists() )
316  {
317  // This must be done before anything else...
318  theCodestream.set_persistent();
319 
320  theCodestream.enable_restart(); // ????
321 
322  // Get the image and tile dimensions.
324  theJp2Dims,
325  theJp2TileDims) )
326  {
327  //---
328  // Set the image size.
329  //
330  // NOTE:
331  //
332  // The geojp2 doqq's that I have all have an offset in them. In
333  // other words the "pos" from "get_dims" is not always 0,0. I
334  // think this was intended for mosaicing without any projection. I
335  // do NOT think it was intended to be used as a sub image offset
336  // into the projection picked up by the geotiff_box. If this were
337  // so the current code here would not mosaic correctly.
338  //
339  // This may not be the case though with all data sets... In which
340  // case some kind of logic would have to be added to this code.
341  //---
343  0,
344  theJp2Dims[0].width() -1,
345  theJp2Dims[0].height()-1);
346 
347  // Number of internal dwl layers
348  theMinDwtLevels = theCodestream.get_min_dwt_levels();
349 
350  //---
351  // Set up channel mapping for copyRegionToTile if it makes sense.
352  // This will set the number of bands if successful, ignoring the
353  // alpha channel.
354  //---
355  if ( configureChannelMapping() == false )
356  {
358  static_cast<ossim_uint32>(theCodestream.get_num_components(true));
359  }
360 
361  if (traceDebug())
362  {
364  << "codestream::get_num_components(true): "
365  << theCodestream.get_num_components(true)
366  << "\ntheNumberOfBands: " << theNumberOfBands << "\n";
367  }
368 
369  //---
370  // Set the cache tile size. Use the internal j2k tile size if it's
371  // reasonable else clamp to some max. Some j2k writer make one
372  // BIG tile so this must be done.
373  //---
374  const ossim_uint32 MAX_CACHE_TILE_DIMENSION = 1024;
375  theCacheSize.x =
376  static_cast<ossim_int32>(
377  (theJp2TileDims[0].width() <= MAX_CACHE_TILE_DIMENSION) ?
378  theJp2TileDims[0].width() : MAX_CACHE_TILE_DIMENSION );
379  theCacheSize.y =
380  static_cast<ossim_int32>(
381  (theJp2TileDims[0].height() <= MAX_CACHE_TILE_DIMENSION) ?
382  theJp2TileDims[0].height() : MAX_CACHE_TILE_DIMENSION );
383 
384  // Set the scalar:
385  int bitDepth = theCodestream.get_bit_depth(0, true);
386  bool isSigned = theCodestream.get_signed(0, true);
387 
388  switch (bitDepth)
389  {
390  case 8:
391  {
393  break;
394  }
395  case 11:
396  {
398  break;
399  }
400  case 12:
401  {
403  break;
404  }
405  case 13:
406  {
408  break;
409  }
410  case 14:
411  {
413  break;
414  }
415  case 15:
416  {
418  break;
419  }
420  case 16:
421  {
423  break;
424  }
425  default:
426  {
428  break;
429  }
430  }
431 
433  {
434  // Initialize the cache.
435  if (theCacheId != -1)
436  {
438  theCacheId = -1;
439  }
440 
441  ossimIrect fullImgRect = theImageRect;
442  fullImgRect.stretchToTileBoundary(theCacheSize);
443 
445  newTileCache(fullImgRect, theCacheSize);
446 
447  // Initialize the tile we will return.
448  initializeTile();
449 
450  // Call the base complete open to pick up overviews.
451  completeOpen();
452 
453 
454  // We should be good now so set the return result to true.
455  result = true;
456 
457  if (traceDebug())
458  {
460  theCodestream);
462  << "\ntheImageRect: " << theImageRect
463  << "\nFull image rect: " << fullImgRect
464  << "\ntheCacheSize: " << theCacheSize
465  << "\nscalar type: "
467  getEntryString(theScalarType)
468  << "\n";
469 
470  for (ossim_uint32 level=0;
471  level < theJp2Dims.size(); ++level)
472  {
474  << "theJp2Dims[" << level << "]: "
475  << theJp2Dims[level]
476  << "\ntheJp2TileDims[" << level << "]: "
477  << theJp2TileDims[level] << "\n";
478  }
480  << "threads: " << threads << endl;
481  }
482 
483  } // if (theScalarType != OSSIM_SCALAR_UNKNOWN)
484 
485  } // matches: if ( ossim::getCodestreamDimensions
486 
487  } // matches: if ( theCodestream.exists() )
488 
489  } // if (theJp2FamilySrc->exists())
490 
491  if (traceDebug())
492  {
494  << MODULE << " exit status = " << (result?"true":"false\n")
495  << std::endl;
496  }
497 
498  return result;
499 
500  if (traceDebug())
501  {
503  << MODULE << " exit status = " << (result?"true":"false\n")
504  << std::endl;
505  }
506 
507  return result;
508 }
509 
511 {
512  return theTile.valid();
513 
514  // return theCodestream.exists()
515  // return theFileStr.is_open();
516 }
517 
519 {
520  // Cleanup processing environment
521  if ( theThreadEnv )
522  {
523  theThreadEnv->join(NULL,true); // Wait until all internal processing is complete.
524  theThreadEnv->terminate(theOpenTileThreadQueue, true);
525  theThreadEnv->cs_terminate(theCodestream); // Terminates background codestream processing.
526  theThreadEnv->destroy();
527  delete theThreadEnv;
528  theThreadEnv = 0;
529  }
530 
531  theTile = 0;
532  theCacheTile = 0;
533 
534  if (theChannels)
535  {
536  theChannels->clear();
537  delete theChannels;
538  theChannels = 0;
539  }
540  if(theCodestream.exists())
541  {
542  theCodestream.destroy();
543  }
544 
545  if (theJp2Source)
546  {
547  delete theJp2Source;
548  theJp2Source = 0;
549  }
550 
551  if (theJp2FamilySrc)
552  {
553  delete theJp2FamilySrc;
554  theJp2FamilySrc = 0;
555  }
556 
558  {
560  }
561 
562  if (theCacheId != -1)
563  {
565  theCacheId = -1;
566  }
567 
569 }
570 
572  const ossimIrect& rect, ossim_uint32 resLevel)
573 {
574  // This tile source bypassed, or invalid res level, return null tile.
575  if(!isSourceEnabled() || !isOpen() || !isValidRLevel(resLevel))
576  {
578  }
579 
580  if (theTile.valid())
581  {
582  // Rectangle must be set prior to getOverviewTile call.
583  theTile->setImageRectangle(rect);
584 
585  if (resLevel)
586  {
587  if ( getOverviewTile(resLevel, theTile.get()) == false )
588  {
589  theTile->makeBlank();
590  }
591  }
592  else // r0
593  {
594  // NOTE: Using cache for r0 tiles.
595 
596  //---
597  // See if the whole tile is going to be filled, if not, start out with
598  // a blank tile so data from a previous load gets wiped out.
599  //---
600  if ( !rect.completely_within(theImageRect) )
601  {
602  // Start with a blank tile.
603  theTile->makeBlank();
604  }
605 
606  //---
607  // See if any point of the requested tile is in the image.
608  //---
609  if ( rect.intersects(theImageRect) )
610  {
611  ossimIrect clipRect = rect.clipToRect(theImageRect);
612 
613  ossimIrect expandedRect = clipRect;
614  expandedRect.stretchToTileBoundary(theCacheSize);
615 
616  //---
617  // Shift the upper left corner of the "clip_rect" to the an even
618  // j2k tile boundry.
619  //---
620  ossimIpt tileOrigin = expandedRect.ul();
621 
622  // Vertical tile loop.
623  while (tileOrigin.y < expandedRect.lr().y)
624  {
625  // Horizontal tile loop.
626  while (tileOrigin.x < expandedRect.lr().x)
627  {
628  if ( loadTileFromCache(tileOrigin, clipRect) == false )
629  {
630  if ( loadTile(tileOrigin) )
631  {
632  //---
633  // Note: Clip the cache tile to the image clipRect
634  // since there are j2k tiles that go beyond the image
635  // dimensions, i.e., edge tiles.
636  //---
637  ossimIrect cr =
639  clipToRect(clipRect);
640 
643  cr,
644  OSSIM_BSQ);
645  }
646 
647  }
648 
649  tileOrigin.x += theCacheSize.x; // Go to next tile.
650 
651  } // End loop in x direction.
652 
653  // Go to next row of tiles.
654  tileOrigin.x = expandedRect.ul().x;
655  tileOrigin.y += theCacheSize.y;
656 
657  } // End loop in y direction.
658 
659  // Set the tile status.
660  theTile->validate();
661 
662  } // matches: if ( rect.intersects(theImageRect) )
663 
664  } // r0 block
665 
666  } // matches: if (theTile.valid())
667 
668  return theTile;
669 }
670 
672  ossimImageData* result)
673 {
674  bool status = false;
675 
676  if ( (resLevel < getNumberOfDecimationLevels()) && result &&
677  (result->getNumberOfBands() == getNumberOfOutputBands()) )
678  {
679  if (resLevel <= theMinDwtLevels)
680  {
681  // Using internal overviews.
682 
683  //---
684  // NOTE:
685  //
686  // The geojp2 doqq's that I have all have an offset in them. In
687  // other words the "pos" from "get_dims" is not always 0,0. I
688  // think this was intended for mosaicing without any projection. I
689  // do NOT think it was intended to be used as a sub image offset
690  // into the projection picked up by the geotiff_box. If this were
691  // so the current code here would not mosaic correctly.
692  //
693  // This may not be the case though with all data sets... In which
694  // case some kind of logic would have to be added to this code.
695  //---
696  ossimIrect originalTileRect = result->getImageRectangle();
697 
698  ossimIrect shiftedRect = originalTileRect + theJp2Dims[resLevel].ul();
699 
700  result->setImageRectangle(shiftedRect);
701 
702  try
703  {
704  if ( theChannels )
705  {
708  static_cast<int>(resLevel),
709  theThreadEnv,
711  result);
712  }
713  else
714  {
716  static_cast<int>(resLevel),
717  theThreadEnv,
719  result);
720  }
721  }
722  catch(const ossimException& e)
723  {
725  << __FILE__ << " " << __LINE__ << " caught exception\n"
726  << e.what();
727  status = false;
728  }
729 
730  // Set the rect back.
731  result->setImageRectangle(originalTileRect);
732 
733  } // matches: if (resLevel <= theMinDwtLevels)
734  else
735  {
736  // Using external overview.
737  status = theOverview->getTile(result, resLevel);
738  }
739  }
740 
741  return status;
742 }
743 
745 {
746  return theNumberOfBands;
747 }
748 
750 {
751  return theNumberOfBands;
752 }
753 
755 {
756  ossim_uint32 result = 0;
757  if ( theJp2TileDims.size() )
758  {
759  if ( theJp2TileDims[0].width() != theImageRect.width() )
760  {
761  // Not a single tile.
762  result = theJp2TileDims[0].width();
763  }
764  }
765  return result;
766 }
767 
769 {
770  ossim_uint32 result = 0;
771  if ( theJp2TileDims.size() )
772  {
773  if ( theJp2TileDims[0].height() != theImageRect.height() )
774  {
775  // Not a single tile.
776  result = static_cast<ossim_uint32>(theJp2TileDims[0].height());
777  }
778  }
779  return result;
780 }
781 
783 {
784  return theScalarType;
785 }
786 
788 {
789  ossim_uint32 width = this->getImageTileWidth();
790  ossim_uint32 height = this->getImageTileHeight();
791 
792  // Check for zero width, height and limit output tile sizes to 1024.
793  if ( !width || !height || ( width > 1024) || (height > 1024) )
794  {
795  ossimIpt tileSize;
796  ossim::defaultTileSize(tileSize);
797 
798  width = tileSize.x;
799  height = tileSize.y;
800  }
801 
803  create( this,
804  this->getOutputScalarType(),
805  this->getNumberOfOutputBands(),
806  width,
807  height);
808 
809  theTile->initialize();
810 
812  create( this,
813  this->getOutputScalarType(),
814  this->getNumberOfOutputBands(),
815  theCacheSize.x,
816  theCacheSize.y );
817 
819 }
820 
822  const ossimIrect& clipRect)
823 {
824  bool result = false;
825 
826  ossimRefPtr<ossimImageData> tempTile =
828  if (tempTile.valid())
829  {
830  //---
831  // Note: Clip the cache j2k tile to the image clipRect since
832  // there are j2k tiles that go beyond the image dimensions, i.e.,
833  // edge tiles.
834  //---
835  ossimIrect cr = tempTile->getImageRectangle().clipToRect(clipRect);
836 
837  theTile->loadTile(tempTile.get()->getBuf(),
838  tempTile->getImageRectangle(),
839  cr,
840  OSSIM_BSQ);
841  result = true;
842  }
843 
844  return result;
845 }
846 
848 {
849  bool result = true;
850 
851  ossimIpt lr(origin.x + theCacheSize.x - 1,
852  origin.y + theCacheSize.y - 1);
853 
854  // Set the cache rectangle to be an even j2k tile.
856 
857  // Let the getOverviewTile do the rest of the work.
858  if ( getOverviewTile(0, theCacheTile.get()) )
859  {
860  // Add it to the cache for the next time.
862  }
863  else
864  {
866  << __FILE__ << __LINE__
867  << " ossimKakaduJp2Reader::loadBlock failed!"
868  << std::endl;
869  result = false;
870  }
871 
872  return result;
873 }
874 
876 {
877  if ( !theGeometry )
878  {
879  //---
880  // Check for external geom - this is a file.geom not to be confused with
881  // geometries picked up from dot.xml, dot.prj, dot.j2w and so on. We
882  // will check for that later if the getInternalImageGeometry fails.
883  //---
885 
886  if ( !theGeometry )
887  {
888  //---
889  // Check for external files other than .geom, i.e. file.xml & j2w:
890  //---
892 
893  if ( !theGeometry )
894  {
895  // Check the internal geometry first to avoid a factory call.
897 
898  //---
899  // WARNING:
900  // Must create/set the geometry at this point or the next call to
901  // ossimImageGeometryRegistry::extendGeometry will put us in an infinite loop
902  // as it does a recursive call back to ossimImageHandler::getImageGeometry().
903  //---
904  if ( !theGeometry )
905  {
907  }
908 
909  // Check for set projection.
910  if ( !theGeometry->getProjection() )
911  {
912  // Last try factories for projection.
914  }
915  }
916  }
917 
918  // Set image things the geometry object should know about.
920  }
921  return theGeometry;
922 }
923 
925 {
926  static const char MODULE[] = "ossimKakaduJp2Reader::getInternalImageGeometry";
927 
928  if (traceDebug())
929  {
930  ossimNotify(ossimNotifyLevel_DEBUG) << MODULE << " entered...\n";
931  }
932 
934 
935  if ( isOpen() )
936  {
937  // Try to get geom from GML box:
939 
940  if ( geom.valid() == false )
941  {
942  // Try to get geom from geotiff box:
944  }
945  }
946 
947  if (traceDebug())
948  {
949  ossimNotify(ossimNotifyLevel_DEBUG) << MODULE << " exited...\n";
950  }
951 
952  return geom;
953 
954 } // End: ossimKakaduJp2Reader::getInternalImageGeometry()
955 
957 {
958  static const char MODULE[] = "ossimKakaduJp2Reader::getImageGeometryFromGeotiffBox";
959 
960  if (traceDebug())
961  {
962  ossimNotify(ossimNotifyLevel_DEBUG) << MODULE << " entered...\n";
963  }
964 
966 
967  if ( isOpen() )
968  {
969  std::ifstream str;
970  str.open( theImageFile.c_str(), std::ios_base::in | std::ios_base::binary);
971 
972  if ( str.is_open() )
973  {
974  std::vector<ossim_uint8> box;
975  ossimJp2Info jp2Info;
976 
977  std::streamoff boxPos = jp2Info.getGeotiffBox( str, box );
978 
979  if ( box.size() )
980  {
981  if (traceDebug())
982  {
984  << "Found geotiff uuid at: " << boxPos+8 << "\n";
985  }
986 
987  //---
988  // Create a string stream and set the vector buffer as its source.
989  // Note: The box has the 16 GEOTIFF_UUID bytes in there so offset
990  // address and size.
991  //---
992 #if 0
993  // This doesn't work with VS2010...
994  // Create a string stream and set the vector buffer as its source.
995  std::istringstream boxStream;
996  boxStream.rdbuf()->pubsetbuf( (char*)&box.front()+GEOTIFF_UUID_SIZE,
997  box.size()-GEOTIFF_UUID_SIZE );
998 #else
999  // convert the vector into a string
1000  std::string boxString( box.begin()+GEOTIFF_UUID_SIZE, box.end() );
1001  std::istringstream boxStream;
1002  boxStream.str( boxString );
1003 #endif
1004 
1005  // Give the stream to tiff info to create a geometry.
1006  ossimTiffInfo info;
1007  ossim_uint32 entry = 0;
1008  ossimKeywordlist kwl; // Used to capture geometry data.
1009 
1010  if ( info.getImageGeometry(boxStream, kwl, entry) )
1011  {
1012  //---
1013  // The tiff embedded in the geojp2 only has one line
1014  // and one sample by design so overwrite the lines and
1015  // samples with the real value.
1016  //---
1017  ossimString pfx = "image";
1018  pfx += ossimString::toString(entry);
1019  pfx += ".";
1020 
1021  // Add the lines.
1023  getNumberOfLines(0), true);
1024 
1025  // Add the samples.
1027  getNumberOfSamples(0), true);
1028 
1029  // Create the projection.
1032  if ( proj.valid() )
1033  {
1034  // Create and assign projection to our ossimImageGeometry object.
1035  geom = new ossimImageGeometry();
1036  geom->setProjection( proj.get() );
1037  if (traceDebug())
1038  {
1039  ossimNotify(ossimNotifyLevel_DEBUG) << "Found GeoTIFF box." << std::endl;
1040  }
1041 
1042  // Get the internal raster pixel alignment type and set the base class.
1043  const char* lookup = kwl.find(pfx.chars(), ossimKeywordNames::PIXEL_TYPE_KW);
1044  if ( lookup )
1045  {
1046  ossimString type = lookup;
1047  type.downcase();
1048  if ( type == "pixel_is_area" )
1049  {
1051  }
1052  else if ( type == "pixel_is_point" )
1053  {
1055  }
1056  }
1057  }
1058  }
1059  }
1060  }
1061  }
1062 
1063  if (traceDebug())
1064  {
1065  ossimNotify(ossimNotifyLevel_DEBUG) << MODULE << " exited...\n";
1066  }
1067 
1068  return geom;
1069 
1070 } // End: ossimKakaduJp2Reader::getImageGeometryFromGeotiffBox
1071 
1072 
1074 {
1075  static const char M[] = "ossimKakaduJp2Reader::getImageGeometryFromGmlBox";
1076 
1077  if (traceDebug())
1078  {
1079  ossimNotify(ossimNotifyLevel_DEBUG) << M << " entered...\n";
1080  }
1081 
1083 
1084  if ( isOpen() )
1085  {
1086  std::ifstream str;
1087  str.open( theImageFile.c_str(), std::ios_base::in | std::ios_base::binary);
1088 
1089  if ( str.is_open() )
1090  {
1091  std::vector<ossim_uint8> box;
1092  ossimJp2Info jp2Info;
1093 
1094  std::streamoff boxPos = jp2Info.getGmlBox( str, box );
1095 
1096  if ( boxPos && box.size() )
1097  {
1098  if (traceDebug())
1099  {
1101  << "Found gml box at: " << boxPos+8
1102  << "\nbox size: " << box.size() << "\n";
1103  }
1104 
1105 #if 0
1106  // This doesn't work with VS2010...
1107  // Create a string stream and set the vector buffer as its source.
1108  std::istringstream boxStream;
1109  boxStream.rdbuf()->pubsetbuf( (char*)&box.front(), box.size() );
1110 #else
1111  // convert the vector into a string
1112  std::string boxString( box.begin(), box.end() );
1113  std::istringstream boxStream;
1114  boxStream.str( boxString );
1115 #endif
1116 
1118 
1119  if ( gml->initialize( boxStream ) )
1120  {
1121  ossimKeywordlist geomKwl;
1122  if ( gml->getImageGeometry( geomKwl ) )
1123  {
1124  // Make projection:
1125  // Create the projection.
1128  if ( proj.valid() )
1129  {
1130  // Create and assign projection to our ossimImageGeometry object.
1131  geom = new ossimImageGeometry();
1132  geom->setProjection( proj.get() );
1133  }
1134  }
1135  }
1136 
1137  // Cleanup:
1138  delete gml;
1139  gml = 0;
1140  }
1141  }
1142  }
1143 
1144  if (traceDebug())
1145  {
1147  << M << " exit status = " << (geom.valid()?"true":"false\n")
1148  << std::endl;
1149  }
1150 
1151  return geom;
1152 
1153 } // End: ossimKakaduJp2Reader::getImageGeometryFromGmlBox
1154 
1155 
1157 {
1158  static const char M[] = "ossimKakaduJp2Reader::getMetadataImageGeometry";
1159  if ( traceDebug() )
1160  {
1161  ossimNotify(ossimNotifyLevel_DEBUG) << M << " entered...\n";
1162  }
1163 
1166 
1167  // See if we can pick up the projection from the FGDC file:
1168  ossimFilename fdgcFile = theImageFile;
1169 
1170  fdgcFile += ".xml"; // file.jp2.xml
1171  if ( fdgcFile.exists() == false )
1172  {
1173  fdgcFile = theImageFile;
1174  fdgcFile.setExtension(ossimString("xml")); // file.xml
1175  }
1176 
1177  if ( fdgcFile.exists() )
1178  {
1179  ossimFgdcXmlDoc fgdcDoc;
1180  if ( fgdcDoc.open(fdgcFile) )
1181  {
1182  try
1183  {
1184  proj = fgdcDoc.getGridCoordSysProjection();
1185  }
1186  catch (const ossimException& e)
1187  {
1188  ossimNotify(ossimNotifyLevel_WARN) << e.what() << std::endl;
1189  }
1190 
1191  if ( proj.valid() )
1192  {
1193  geom = new ossimImageGeometry();
1194 
1195  ossimMapProjection* mapProj = dynamic_cast<ossimMapProjection*>(proj.get());
1196  if ( mapProj )
1197  {
1198  // See if we have a world file. Seems they have a more accurate tie point.
1199  ossimFilename worldFile = theImageFile;
1200  worldFile.setExtension(ossimString("j2w")); // file.j2w
1201  if ( worldFile.exists() )
1202  {
1203  //---
1204  // Note need a way to determine pixel type from fgdc doc.
1205  // This can result in a half pixel shift.
1206  //---
1208  ossimUnitType unitType = fgdcDoc.getUnitType();
1209 
1210  ossimTiffWorld tfw;
1211  if ( tfw.open(worldFile, pixelType, unitType) )
1212  {
1213  ossimDpt gsd = tfw.getScale();
1214  gsd.y = std::fabs(gsd.y); // y positive up so negate.
1215  ossimDpt tie = tfw.getTranslation();
1216 
1217  if ( unitType != OSSIM_METERS )
1218  {
1220 
1221  // GSD (scale):
1222  uct.setValue(gsd.x, unitType);
1223  gsd.x = uct.getValue(OSSIM_METERS);
1224  uct.setValue(gsd.y, unitType);
1225  gsd.y = uct.getValue(OSSIM_METERS);
1226 
1227  // Tie point:
1228  uct.setValue(tie.x, unitType);
1229  tie.x = uct.getValue(OSSIM_METERS);
1230  uct.setValue(tie.y, unitType);
1231  tie.y = uct.getValue(OSSIM_METERS);
1232  }
1233 
1234  mapProj->setMetersPerPixel(gsd);
1235  mapProj->setUlTiePoints(tie);
1236  }
1237 
1238  if ( tfw.getRotation() != 0.0 )
1239  {
1241  << M << " Unhandled rotation in tfw file." << std::endl;
1242  }
1243  }
1244 
1245  } // if ( worldFile.exists() )
1246 
1247  geom->setProjection( proj.get() );
1248 
1249  } // if ( proj.valid() )
1250 
1251  } // if ( fgdcDoc.open(fdgcFile) )
1252 
1253  } // if ( fdgcFile.exists() )
1254 
1255  if (traceDebug())
1256  {
1258  << M << " exit status = " << (geom.valid()?"true":"false\n")
1259  << std::endl;
1260  }
1261 
1262  return geom;
1263 }
1264 
1266  const char* prefix)
1267 {
1268  bool result = false;
1269  if ( ossimImageHandler::loadState(kwl, prefix) )
1270  {
1271  result = open();
1272  }
1273  return result;
1274 }
1275 
1277 {
1278  bool result = false;
1279 
1280  if ( theChannels )
1281  {
1282  theChannels->clear();
1283  }
1284  else
1285  {
1286  theChannels = new kdu_supp::kdu_channel_mapping;
1287  }
1288 
1289  if ( theJp2Source )
1290  {
1291  // bool flag "ignore_alpha", turns on off alpha channel.
1292  result = theChannels->configure(static_cast<kdu_supp::jp2_source*>(theJp2Source), true);
1293  }
1294  else
1295  {
1296  result = theChannels->configure(theCodestream);
1297  }
1298 
1299  if ( result )
1300  {
1301  theNumberOfBands = (ossim_uint32)theChannels->get_num_colour_channels();
1302 
1303  if (traceDebug())
1304  {
1306  << "ossimKakaduJp2Reader::configureChannelMapping() DEBUG:"
1307  << "\nkdu_channel_mapping::get_num_channels(): "
1308  << theChannels->get_num_channels()
1309  << "\nkdu_channel_mapping::get_num_colour_channels(): "
1310  << theChannels->get_num_colour_channels()
1311  << "\ntheNumberOfBands: " << theNumberOfBands << endl;
1312  }
1313  }
1314 
1315  // Force a per component kdu region decompress.
1316  if ( !result || ( theNumberOfBands != (ossim_uint32)theChannels->get_num_channels() ) )
1317  {
1318  // Remove the channel mapping.
1319  theChannels->clear();
1320  delete theChannels;
1321  theChannels = 0;
1322  }
1323 
1324  return result;
1325 }
1326 
virtual void deleteCache(ossimAppFixedCacheId cacheId)
virtual bool getOverviewTile(ossim_uint32 resLevel, ossimImageData *result)
Gets an overview tile.
kdu_core::kdu_compressed_source * theJp2Source
virtual bool isSourceEnabled() const
Definition: ossimSource.cpp:79
bool open(const ossimFilename &file, ossimPixelType ptype, ossimUnitType unit)
static ossimImageGeometryRegistry * instance()
ossimRefPtr< ossimImageGeometry > theGeometry
ossimRefPtr< ossimImageData > theTile
virtual ossim_uint32 getImageTileHeight() const
Returns the tile width of the image or 0 if the image is not tiled.
double getValue(ossimUnitType unitType=OSSIM_METERS) const
void setProjection(ossimProjection *projection)
Sets the projection to be used for local-to-world coordinate transformation.
16 bit unsigned integer (12 bits used)
virtual ossim_uint32 getNumberOfBands() const
bool loadTile(const ossimIpt &origin)
Loads a block of data to theCacheTile.
virtual ossim_uint32 getNumberOfLines(ossim_uint32 resLevel=0) const
Gets number of lines for res level.
ossimFilename theImageFile
virtual ossimRefPtr< ossimImageData > getTile(const ossimIrect &rect, ossim_uint32 resLevel=0)
Method to grab a tile(rectangle) from image.
virtual void setImageRectangle(const ossimIrect &rect)
16 bit unsigned integer
ossimKakaduJp2Reader class for reading images with JPEG2000 (J2K) compressed blocks using kakadu libr...
ossimUnitType
Represents serializable keyword/value map.
std::basic_ifstream< char > ifstream
Class for char input file streams.
Definition: ossimIosFwd.h:44
virtual bool loadState(const ossimKeywordlist &kwl, const char *prefix=0)
Method to the load (recreate) the state of an object from a keyword list.
bool valid() const
Definition: ossimRefPtr.h:75
kdu_core::kdu_thread_queue * theOpenTileThreadQueue
const char * find(const char *key) const
16 bit unsigned integer (14 bits used)
virtual bool loadState(const ossimKeywordlist &kwl, const char *prefix=0)
Method to the load (recreate) the state of an object from a keyword list.
virtual ossim_uint32 getNumberOfLines(ossim_uint32 resLevel=0) const =0
Pure virtual, derived classes must implement.
void initializeTile()
Initializes data member "theTile".
void setValue(double value, ossimUnitType unitType=OSSIM_METERS)
double y
Definition: ossimDpt.h:165
ossim_uint32 height() const
Definition: ossimIrect.h:487
ossimRefPtr< ossimImageGeometry > getMetadataImageGeometry() const
bool getImageGeometry(ossimKeywordlist &geomKwl, ossim_uint32 entryIndex) const
Extracts geometry info to keyword list.
ossimRefPtr< ossimProjection > getGridCoordSysProjection()
Gets projection from Grid Coordinate system node.
static ossimString toString(bool aValue)
Numeric to string methods.
static const char * NUMBER_LINES_KW
kdu_core::kdu_codestream theCodestream
virtual ossim_uint32 getNumberOfOutputBands() const
Returns the number of bands in a tile returned from this TileSource.
OSSIM_DLL void defaultTileSize(ossimIpt &tileSize)
16 bit signed integer
virtual void closeEntry()
Method to close current entry.
const ossimIpt & ul() const
Definition: ossimIrect.h:274
ossim_uint32 toUInt32() const
16 bit unsigned integer (13 bits used)
bool intersects(const ossimIrect &rect) const
Definition: ossimIrect.cpp:183
TIFF info class.
Definition: ossimTiffInfo.h:36
bool isJp2()
Test first 12 bytes of file for the jp2 signature block.
std::vector< ossimIrect > theJp2TileDims
Tile dimensions for each level.
virtual ossimString getClassName() const
Returns class name.
virtual bool extendGeometry(ossimImageHandler *handler) const
virtual void initialize()
Initialize the data buffer.
static ossimAppFixedTileCache * instance(ossim_uint32 maxSize=0)
virtual ~ossimKakaduJp2Reader()
virtural destructor
virtual void setMetersPerPixel(const ossimDpt &gsd)
ossimPixelType thePixelType
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.
bool completely_within(const ossimIrect &rect) const
Definition: ossimIrect.cpp:425
virtual ossimString getLongName() const
Returns long name.
GML support data class.
bool loadTileFromCache(const ossimIpt &origin, const ossimIrect &clipRect)
Loads a block of data to theCacheTile from the cache.
bool getImageGeometry(ossimKeywordlist &geomKwl) const
Extracts geometry info to keyword list.
void add(const char *prefix, const ossimKeywordlist &kwl, bool overwrite=true)
virtual void loadTile(const void *src, const ossimIrect &src_rect, ossimInterleaveType il_type)
static ossimScalarTypeLut * instance()
Returns the static instance of an ossimScalarTypeLut object.
kdu_core::kdu_thread_env * theThreadEnv
static ossimImageDataFactory * instance()
ossimRefPtr< ossimImageData > theCacheTile
OSSIM_DLL bool isSigned(ossimScalarType scalarType)
ossimProjection * createProjection(const ossimFilename &filename, ossim_uint32 entryIdx) const
ossimRefPtr< ossimImageData > getTile(ossimAppFixedCacheId cacheId, const ossimIpt &origin)
const char * findPreference(const char *key) const
kdu_supp::jp2_family_src * theJp2FamilySrc
virtual ossimDataObjectStatus validate() const
bool exists() const
virtual const char * what() const
Returns the error message.
virtual ossim_uint32 getNumberOfDecimationLevels() const
Returns the number of decimation levels.
std::ostream & print(std::ostream &out, kdu_core::kdu_codestream &cs)
Convenience print method for kdu_codestream.
JP2 info class.
Definition: ossimJp2Info.h:21
unsigned int ossim_uint32
virtual bool open()
Open method.
const char * chars() const
For backward compatibility.
Definition: ossimString.h:77
virtual ossimRefPtr< ossimImageGeometry > getImageGeometryFromGmlBox()
virtual ossimRefPtr< ossimImageGeometry > getImageGeometry()
Returns the image geometry object associated with this tile source or NULL if non defined...
Class for FGDC XML doc parsing.
virtual ossimIrect getImageRectangle() const
bool configureChannelMapping()
Initializes m_channels to be used with copyRegionToTile if it makes sense.
ossimScalarType theScalarType
const ossimIpt & lr() const
Definition: ossimIrect.h:276
virtual void close()
Deletes the overview and clears the valid image vertices.
static ossimString downcase(const ossimString &aString)
Definition: ossimString.cpp:48
bool initialize(const ossimImageGeometry *geom, const ossimIrect &rect)
Initializes gml block from geometry file.
ossim_uint32 width() const
Definition: ossimIrect.h:500
void initImageParameters(ossimImageGeometry *geom) const
Convenience method to set things needed in the image geometry from the image handler.
ossimIrect clipToRect(const ossimIrect &rect) const
Definition: ossimIrect.cpp:501
static ossimPreferences * instance()
Container class that holds both 2D transform and 3D projection information for an image Only one inst...
ossimScalarType
static ossimProjectionFactoryRegistry * instance()
virtual ossimScalarType getOutputScalarType() const
Returns the output pixel type of the tile source.
virtual ossimRefPtr< ossimImageGeometry > getExternalImageGeometry() const
Returns the image geometry object associated with this tile source or NULL if non defined...
return status
virtual void makeBlank()
Initializes data to null pixel values.
const ossimProjection * getProjection() const
Access methods for projection (may be NULL pointer).
virtual void completeOpen()
Will complete the opening process.
16 bit unsigned integer (15 bits used)
ossimPixelType
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 ossimRefPtr< ossimImageGeometry > getImageGeometryFromGeotiffBox()
This class defines an abstract Handler which all image handlers(loaders) should derive from...
const ossimDpt & getScale() const
Converts world file parameters into x, y scale (for use in affine transform)
ossimKakaduJp2Reader()
default construtor
virtual ossim_uint32 getNumberOfInputBands() const
Returns the number of bands in the image.
ossim_int32 y
Definition: ossimIpt.h:142
virtual const void * getBuf() const
static const char * PIXEL_TYPE_KW
std::vector< ossimIrect > theJp2Dims
Has sub image offset.
double x
Definition: ossimDpt.h:164
const ossimDpt & getTranslation() const
Provides access to the translation (for use in affine transform)
const char * c_str() const
Returns a pointer to a null-terminated array of characters representing the string&#39;s contents...
Definition: ossimString.h:396
void stretchToTileBoundary(const ossimIpt &tileWidthHeight)
Definition: ossimIrect.cpp:212
virtual ossim_uint32 getImageTileWidth() const
Returns the tile width of the image or 0 if the image is not tiled.
bool openJp2File()
Opens the jp2 and initializes this object.
RTTI_DEF1_INST(ossimKakaduJp2Reader, "ossimKakaduJp2Reader", ossimImageHandler) ossimKakaduJp2Reader
virtual void setUlTiePoints(const ossimGpt &gpt)
bool open(const ossimFilename &xmlFileName)
Open method.
virtual ossim_uint32 getNumberOfSamples(ossim_uint32 resLevel=0) const =0
Pure virtual, derived classes must implement.
ossim_int32 x
Definition: ossimIpt.h:141
double getRotation() const
Converts world file parameters into RH rotation in radians (for use in affine transform) ...
8 bit unsigned integer
std::basic_istringstream< char > istringstream
Class for char input memory streams.
Definition: ossimIosFwd.h:32
virtual ossim_uint32 getNumberOfSamples(ossim_uint32 resLevel=0) const
Gets the number of samples for res level.
std::streamoff getGmlBox(std::ifstream &str, std::vector< ossim_uint8 > &box) const
Method to get the embedded JP2 GML Box.
virtual ossimRefPtr< ossimImageGeometry > getInternalImageGeometry()
virtual bool isOpen() const
Method to test for open file stream.
ossimFilename & setExtension(const ossimString &e)
Sets the extension of a file name.
ossimUnitType getUnitType() const
std::streamoff getGeotiffBox(std::ifstream &str, std::vector< ossim_uint8 > &box) const
Method to get the embedded JP2 GeoTIFF box.
16 bit unsigned integer (11 bits used)
virtual ossimString getShortName() const
Returns short name.
ossimAppFixedTileCache::ossimAppFixedCacheId theCacheId
Cache initialized to image rect with sub image offset.
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).
static const char * NUMBER_SAMPLES_KW
unsigned char ossim_uint8
ossimRefPtr< ossimImageData > addTile(ossimAppFixedCacheId cacheId, ossimRefPtr< ossimImageData > data, bool duplicateData=true)
OSSIMDLLEXPORT std::ostream & ossimNotify(ossimNotifyLevel level=ossimNotifyLevel_WARN)
int ossim_int32
virtual ossimRefPtr< ossimImageData > getTile(const ossimIpt &origin, ossim_uint32 resLevel=0)
kdu_supp::kdu_channel_mapping * theChannels