1 //----------------------------------------------------------------------------
2 // File: ossimImageUtil.cpp
3 //
4 // License: MIT
5 //
6 // Author:  David Burken
7 //
8 // Description: ossimImageUtil class definition
9 //
10 // Utility class for processing image recursively.  This is for doing things like:
11 // building overview, histograms, compute min/max, extract vertices.
12 //
13 //----------------------------------------------------------------------------
14 // $Id$
15 
16 #include <ossim/util/ossimImageUtil.h>
17 #include <ossim/base/ossimArgumentParser.h>
18 #include <ossim/base/ossimApplicationUsage.h>
19 #include <ossim/base/ossimCommon.h>
20 #include <ossim/base/ossimContainerProperty.h>
21 #include <ossim/base/ossimDatum.h>
22 #include <ossim/base/ossimDatumFactoryRegistry.h>
23 #include <ossim/base/ossimDrect.h>
24 #include <ossim/base/ossimObjectFactoryRegistry.h>
25 #include <ossim/base/ossimEllipsoid.h>
26 #include <ossim/base/ossimException.h>
27 #include <ossim/base/ossimFilename.h>
28 #include <ossim/base/ossimGeoidManager.h>
29 #include <ossim/base/ossimGpt.h>
30 #include <ossim/init/ossimInit.h>
31 #include <ossim/base/ossimKeywordNames.h>
32 #include <ossim/base/ossimNotify.h>
33 #include <ossim/base/ossimPreferences.h>
34 #include <ossim/base/ossimProperty.h>
35 #include <ossim/base/ossimPropertyInterface.h>
36 #include <ossim/base/ossimScalarTypeLut.h>
37 #include <ossim/base/ossimStdOutProgress.h>
38 #include <ossim/base/ossimString.h>
39 #include <ossim/base/ossimStringProperty.h>
40 #include <ossim/base/ossimTrace.h>
41 #include <ossim/base/ossimXmlDocument.h>
42 #include <ossim/elevation/ossimElevManager.h>
43 #include <ossim/imaging/ossimFilterResampler.h>
44 #include <ossim/imaging/ossimHistogramWriter.h>
45 #include <ossim/imaging/ossimImageGeometry.h>
46 #include <ossim/imaging/ossimImageHandlerRegistry.h>
47 #include <ossim/imaging/ossimImageHistogramSource.h>
48 #include <ossim/imaging/ossimImageWriterFactoryRegistry.h>
49 #include <ossim/imaging/ossimOverviewBuilderFactoryRegistry.h>
50 #include <ossim/init/ossimInit.h>
51 #include <ossim/plugin/ossimSharedPluginRegistry.h>
52 #include <ossim/projection/ossimProjectionFactoryRegistry.h>
53 #include <ossim/support_data/ossimSupportFilesList.h>
54 #include <ossim/util/ossimFileWalker.h>
55 #include <ossim/imaging/ossimBandSelector.h>
56 #include <ossim/imaging/ossimImageHistogramSource.h>
57 #include <ossim/imaging/ossimImageSourceFactoryRegistry.h>
58 #include <ossim/imaging/ossimImageRenderer.h>
59 #include <ossim/imaging/ossimScaleFilter.h>
60 #include <ossim/imaging/ossimImageWriterFactoryRegistry.h>
61 #include <ossim/imaging/ossimHistogramRemapper.h>
62 #include <ossim/imaging/ossimScalarRemapper.h>
63 #include <ossim/imaging/ossimRectangleCutFilter.h>
64 #include <ossim/projection/ossimImageViewAffineTransform.h>
65 
66 #include <cstdlib>
67 #include <iomanip>
68 #include <string>
69 #include <vector>
70 
71 using namespace std;
72 
73 static std::string CMM_MAX_KW                  = "cmm_max"; // CMM(ComputeMinMax)
74 static std::string CMM_MIN_KW                  = "cmm_min";
75 static std::string CMM_NULL_KW                 = "cmm_null";
76 static std::string COPY_ALL_FLAG_KW            = "copy_all_flag";
77 static std::string CREATE_HISTOGRAM_KW         = "create_histogram";
78 static std::string CREATE_HISTOGRAM_FAST_KW    = "create_histogram_fast";
79 static std::string CREATE_HISTOGRAM_R0_KW      = "create_histogram_r0";
80 static std::string CREATE_OVERVIEWS_KW         = "create_overviews";
81 static std::string CREATE_THUMBNAILS_KW        = "create_thumbnails";
82 static std::string DUMP_FILTERED_IMAGES_KW     = "dump_filter_image";
83 static std::string FALSE_KW                    = "false";
84 static std::string FILE_KW                     = "file";
85 static std::string INTERNAL_OVERVIEWS_FLAG_KW  = "internal_overviews_flag";
86 static std::string OUTPUT_DIRECTORY_KW         = "output_directory";
87 static std::string OUTPUT_FILENAMES_KW         = "output_filenames";
88 static std::string OVERRIDE_FILTERED_IMAGES_KW = "override_filtered_images";
89 static std::string OVERVIEW_STOP_DIM_KW        = "overview_stop_dimension";
90 static std::string OVERVIEW_TYPE_KW            = "overview_type";
91 static std::string READER_PROP_KW              = "reader_prop";
92 static std::string REBUILD_HISTOGRAM_KW        = "rebuild_histogram";
93 static std::string REBUILD_OVERVIEWS_KW        = "rebuild_overviews";
94 static std::string SCAN_MIN_MAX_KW             = "scan_for_min_max";
95 static std::string SCAN_MIN_MAX_NULL_KW        = "scan_for_min_max_null";
96 static std::string THREADS_KW                  = "threads";
97 static std::string THUMBNAIL_SIZE_KW           = "thumbnail_size";
98 static std::string THUMBNAIL_STRETCH_TYPE_KW   = "thumbnail_stretch_type";
99 static std::string THUMBNAIL_TYPE_KW           = "thumbnail_type";
100 static std::string TILE_SIZE_KW                = "tile_size";
101 static std::string TRUE_KW                     = "true";
102 static std::string WRITER_PROP_KW              = "writer_prop";
103 
104 // Static trace for debugging.  Use -T ossimImageUtil to turn on.
105 static ossimTrace traceDebug = ossimTrace("ossimImageUtil:debug");
106 
ossimImageUtil()107 ossimImageUtil::ossimImageUtil()
108    :
109    ossimReferenced(),
110    ossimFileProcessorInterface(),
111    m_kwl( new ossimKeywordlist() ),
112    m_fileWalker(0),
113    m_mutex(),
114    m_errorStatus(0),
115    m_filteredImages(0)
116 {
117 }
118 
~ossimImageUtil()119 ossimImageUtil::~ossimImageUtil()
120 {
121    if ( m_fileWalker )
122    {
123       delete m_fileWalker;
124       m_fileWalker = 0;
125    }
126 }
127 
addOptions(ossimApplicationUsage * au)128 void ossimImageUtil::addOptions(ossimApplicationUsage* au)
129 {
130    // Set the command line options:
131    au->addCommandLineOption("-a or --include-fullres", "Copy full res dataset to overview file as well as building reduced res sets. Option only valid with tiff overview builder. Requires -o option.");
132 
133    au->addCommandLineOption("--ch or --create-histogram", "Computes full histogram alongside overview.");
134 
135    au->addCommandLineOption("--chf or --create-histogram-fast", "Computes a histogram in fast mode which samples partial tiles.");
136    au->addCommandLineOption("--ct or --create-thumbnail", "computes a thumbnail of the image");
137    au->addCommandLineOption("--tt or --thumbnail-type", "Can be of of values png or jpeg");
138    au->addCommandLineOption("--tst or --thumbnail-stretch-type", "Can be of values none,auto-minmax,auto-percentile,std-stretch-1,std-stretch-2,std-stretch-3");
139 
140    au->addCommandLineOption("--compression-quality", "Compression quality for TIFF JPEG takes values from 0 to 100, where 100 is best.  For J2K plugin, numerically_lossless, visually_lossless, lossy");
141 
142    au->addCommandLineOption("--compute-min-max", "Turns on min, max scanning when reading tiles and writes a dot omd file. This option assumes the null is known.");
143 
144    au->addCommandLineOption("--compute-min-max-null", "Turns on min, max, null scanning when reading tiles and write a dot omd file. This option tries to find a null value which is useful for float data.");
145 
146    au->addCommandLineOption("--compression-type", "Compression type can be: deflate, jpeg, lzw, none or packbits");
147 
148    au->addCommandLineOption("--create-histogram-r0", "Forces create-histogram code to compute a histogram using r0 instead of the starting resolution for the overview builder. Can require a separate pass of R0 layer if the base image has built in overviews.");
149 
150    au->addCommandLineOption("-d", "<output_directory> Write overview to output directory specified.");
151 
152    au->addCommandLineOption("--dump-filtered-image-list", "Outputs list of filtered images and extensions.");
153 
154    au->addCommandLineOption("-h", "Display this information");
155 
156    au->addCommandLineOption("-i or --internal-overviews", "Builds internal overviews. Requires -o option. Option only valid with tiff input image and tiff overview builder. WARNING: Modifies source image and cannot be undone!");
157 
158    au->addCommandLineOption("--list-entries", "Lists the entries within the image");
159 
160    au->addCommandLineOption("--max","Overrides max value for compute-min-max option.");
161 
162    au->addCommandLineOption("--min","Overrides min value for compute-min-max option.");
163 
164    au->addCommandLineOption("--null", "<null_value> Overrides null value for compute-min-max option.  e.g. -9999.0 for float data");
165 
166    au->addCommandLineOption("-o", "Creates overviews. (default=ossim_tiff_box)");
167 
168    au->addCommandLineOption("--of or --output-files", "Output image files we can open, exluding overviews.");
169 
170    au->addCommandLineOption("--options","<options.kwl>  This can be all or part of the application options. Also used for custom prep, per file and post system commands. To get a template you can turn on trace to the ossimImageUtil class by adding \"-T ossimImageUtil\" to your command.");
171 
172    au->addCommandLineOption("--ot", "<overview_type> Overview type. see list at bottom for valid types. (default=ossim_tiff_box)");
173 
174    au->addCommandLineOption("--override-filtered-images", "Allows processing of file that is in the filtered image list.");
175 
176    au->addCommandLineOption("-r or --rebuild-overviews", "Rebuild overviews even if they are already present.");
177 
178    au->addCommandLineOption("--rebuild-histogram", "Rebuild histogram even if they are already present.");
179 
180    au->addCommandLineOption("--reader-prop", "Adds a property to send to the reader. format is name=value");
181 
182    au->addCommandLineOption("-s",  "Stop dimension for overviews.  This controls how \nmany layers will be built. If set to 64 then the builder will stop when height and width for current level are less than or equal to 64.  Note a default can be set in the ossim preferences file by setting the keyword \"overview_stop_dimension\".");
183 
184    au->addCommandLineOption("--tile-size", "<size> Defines the tile size for overview builder.  Tiff option only. Must be a multiple of 16. Size will be used in both x and y directions. Note a default can be set in your ossim preferences file by setting the key \"tile_size\".");
185 
186    au->addCommandLineOption("--threads", "<threads> The number of threads to use. (default=1) Note a default can be set in your ossim preferences file by setting the key \"ossim_threads\".");
187 
188    au->addCommandLineOption("--writer-prop", "Adds a property to send to the writer. format is name=value");
189 }
190 
addArguments(ossimArgumentParser & ap)191 void ossimImageUtil::addArguments(ossimArgumentParser& ap)
192 {
193    // Set the general usage:
194    ossimApplicationUsage* au = ap.getApplicationUsage();
195    ossimString usageString = ap.getApplicationName();
196    usageString += " [options] <file-or-directory-to-walk>";
197    au->setCommandLineUsage(usageString);
198 
199    addOptions(au);
200 
201 } // void ossimImageUtil::addArguments(ossimArgumentParser& ap)
202 
initialize(ossimArgumentParser & ap)203 bool ossimImageUtil::initialize(ossimArgumentParser& ap)
204 {
205    static const char M[] = "ossimImageUtil::initialize(ossimArgumentParser&)";
206    if ( traceDebug() )
207    {
208       ossimNotify(ossimNotifyLevel_DEBUG) << M << " entered...\n";
209    }
210 
211    bool result = true;
212 
213    if ( (ap.argc() == 1) || ap.read("-h") || ap.read("--help") )
214    {
215       usage(ap);
216 
217       // continue_after_init to false
218       result = false;
219    }
220    else
221    {
222       // Start with clean options keyword list.
223       m_kwl->clear();
224 
225       // Used throughout below:
226       std::string ts1;
227       ossimArgumentParser::ossimParameter sp1(ts1);
228       std::string ts2;
229       ossimArgumentParser::ossimParameter sp2(ts2);
230 
231       while ( 1 ) //  While forever loop...
232       {
233          if( ap.read("-a") || ap.read("--include-fullres") )
234          {
235             setCopyAllFlag( true );
236             if ( ap.argc() < 2 )
237             {
238                break;
239             }
240          }
241 
242          if( ap.read("--compression-quality", sp1) )
243          {
244             if ( ts1.size() )
245             {
246                setCompressionQuality( ts1 );
247             }
248             if ( ap.argc() < 2 )
249             {
250                break;
251             }
252          }
253 
254          if( ap.read("--compression-type", sp1) )
255          {
256             if ( ts1.size() )
257             {
258                setCompressionType( ts1 );
259             }
260             if ( ap.argc() < 2 )
261             {
262                break;
263             }
264          }
265 
266          if( ap.read("--ch") || ap.read("--create-histogram") )
267          {
268             setCreateHistogramFlag( true );
269             if ( ap.argc() < 2 )
270             {
271                break;
272             }
273          }
274 
275          if( ap.read("--chf") || ap.read("--create-histogram-fast") )
276          {
277             setCreateHistogramFastFlag( true );
278             if ( ap.argc() < 2 )
279             {
280                break;
281             }
282          }
283 
284          if( ap.read("--compute-min-max") )
285          {
286             setScanForMinMax( true );
287             if ( ap.argc() < 2 )
288             {
289                break;
290             }
291          }
292 
293          if( ap.read("--compute-min-max-null") )
294          {
295             setScanForMinMaxNull( true );
296             if ( ap.argc() < 2 )
297             {
298                break;
299             }
300          }
301 
302          if( ap.read("--create-histogram-r0") )
303          {
304             setCreateHistogramR0Flag( true );
305             if ( ap.argc() < 2 )
306             {
307                break;
308             }
309          }
310 
311          if( ap.read("-d", sp1) )
312          {
313             setOutputDirectory( ts1 );
314             if ( ap.argc() < 2 )
315             {
316                break;
317             }
318          }
319 
320          if( ap.read("--dump-filtered-image-list") )
321          {
322             setDumpFilteredImageListFlag( true );
323             if ( ap.argc() < 2 )
324             {
325                break;
326             }
327          }
328 
329          if( ap.read("-i") || ap.read("--internal-overviews") )
330          {
331             setInternalOverviewsFlag( true );
332             if ( ap.argc() < 2 )
333             {
334                break;
335             }
336          }
337 
338          if( ap.read("--max", sp1) )
339          {
340             addOption( CMM_MAX_KW, ts1 );
341             if ( ap.argc() < 2 )
342             {
343                break;
344             }
345          }
346 
347          if( ap.read("--min", sp1) )
348          {
349             addOption( CMM_MIN_KW, ts1 );
350             if ( ap.argc() < 2 )
351             {
352                break;
353             }
354          }
355 
356          if( ap.read("--null", sp1) )
357          {
358             addOption( CMM_NULL_KW, ts1 );
359             if ( ap.argc() < 2 )
360             {
361                break;
362             }
363          }
364 
365          if( ap.read("--options", sp1) )
366          {
367             ossimFilename optionsKwl = ts1;
368             if ( optionsKwl.exists() )
369             {
370                if ( m_kwl->addFile(optionsKwl) == false )
371                {
372                   std::string errMsg = "ERROR could not open options keyword list file: ";
373                   errMsg += optionsKwl.string();
374                   throw ossimException(errMsg);
375                }
376             }
377             else
378             {
379                std::string errMsg = "ERROR options keyword list file does not exists: ";
380                errMsg += optionsKwl.string();
381                throw ossimException(errMsg);
382             }
383          }
384 
385          if( ap.read("--of") || ap.read("--output-files") )
386          {
387             setOutputFileNamesFlag( true );
388             if ( ap.argc() < 2 )
389             {
390                break;
391             }
392          }
393 
394          if (ap.read("-o"))
395          {
396             setCreateOverviewsFlag(true);
397             if (ap.argc() < 2)
398             {
399                break;
400             }
401          }
402          if (ap.read("--ct"))
403          {
404             setCreateThumbnailsFlag(true);
405             if (ap.argc() < 2)
406             {
407                break;
408             }
409          }
410          if (ap.read("--tt", sp1) || ap.read("--thumbnail-type", sp1))
411          {
412             setThumbnailType(ts1);
413             if (ap.argc() < 2)
414             {
415                break;
416             }
417          }
418          if (ap.read("--tst", sp1) || ap.read("--thumbnail-stretch-type", sp1))
419          {
420             setThumbnailStretchType(ts1);
421             if (ap.argc() < 2)
422             {
423                break;
424             }
425          }
426 
427          if (ap.read("--ot", sp1))
428          {
429             setOverviewType( ts1 );
430             if ( ap.argc() < 2 )
431             {
432                break;
433             }
434          }
435 
436          if( ap.read("--override-filtered-images") )
437          {
438             setOverrideFilteredImagesFlag( true );
439             if ( ap.argc() < 2 )
440             {
441                break;
442             }
443          }
444 
445          if( ap.read("-r") || ap.read("--rebuild-overviews") )
446          {
447             setRebuildOverviewsFlag( true );
448             if ( ap.argc() < 2 )
449             {
450                break;
451             }
452          }
453 
454          if( ap.read("--rebuild-histogram") )
455          {
456             setRebuildHistogramFlag( true );
457             if ( ap.argc() < 2 )
458             {
459                break;
460             }
461          }
462 
463          while(ap.read("--reader-prop", sp1))
464          {
465             if (ts1.size())
466             {
467                std::string key = READER_PROP_KW;
468                key += ossimString::toString( getNextReaderPropIndex() ).string();
469                addOption( key, ts1 );
470             }
471          }
472          if ( ap.argc() < 2 )
473          {
474             break;
475          }
476 
477          if( ap.read("-s", sp1) )
478          {
479             setOverviewStopDimension( ts1 );
480             if ( ap.argc() < 2 )
481             {
482                break;
483             }
484          }
485 
486          if ( ap.read("--tile-size", sp1))
487          {
488             setTileSize( ossimString(ts1).toInt32() );
489             if ( ap.argc() < 2 )
490             {
491                break;
492             }
493          }
494 
495          if( ap.read("--threads", sp1) )
496          {
497             m_kwl->addPair( THREADS_KW, ts1 );
498             if ( ap.argc() < 2 )
499             {
500                break;
501             }
502          }
503 
504          while(ap.read("--writer-prop", sp1))
505          {
506             if (ts1.size())
507             {
508                std::string key = WRITER_PROP_KW;
509                key += ossimString::toString( getNextWriterPropIndex() ).string();
510                addOption( key, ts1 );
511             }
512          }
513          if ( ap.argc() < 2 )
514          {
515             break;
516          }
517 
518          // End of arg parsing.
519          ap.reportRemainingOptionsAsUnrecognized();
520          if ( ap.errors() )
521          {
522             ap.writeErrorMessages(ossimNotify(ossimNotifyLevel_NOTICE));
523             std::string errMsg = "Unknown option...";
524             throw ossimException(errMsg);
525          }
526 
527          break; // Break from while forever.
528 
529       } // End while (forever) loop.
530 
531       if(ap.argc() > 1)
532       {
533          for (ossim_int32 i = 0; i < (ap.argc()-1); ++i)
534          {
535             ossimString kw = FILE_KW;
536             kw += ossimString::toString(i);
537             std::string value = ap[i+1];
538             m_kwl->addPair(kw.string(), value, true);
539          }
540       }
541       else
542       {
543          if ( getDumpFilterImagesFlag() )
544          {
545             // Caller wants to see filtered image names:
546             if ( m_filteredImages.empty() )
547             {
548                initializeDefaultFilterList();
549             }
550 
551             // Dump our filtered images.
552             dumpFilteredImageList();
553 
554             if ( !m_fileWalker )
555             {
556                m_fileWalker = new ossimFileWalker();
557                m_fileWalker->initializeDefaultFilterList();
558             }
559 
560             // Dump the file walker's filtered extensions.
561             m_fileWalker->dumpFilteredExtensionList();
562          }
563          else
564          {
565             usage(ap);
566          }
567 
568          // continue_after_init to false
569          result = false;
570 
571       }
572 
573    } // not usage
574 
575    if ( traceDebug() )
576    {
577       ossimNotify(ossimNotifyLevel_DEBUG)
578          << "m_kwl:\n" << *(m_kwl.get()) << "\n"
579          << M << " exit result = " << (result?"true":"false")
580          << "\n";
581    }
582 
583    return result;
584 }
585 
execute()586 ossim_int32 ossimImageUtil::execute()
587 {
588    static const char M[] = "ossimImageUtil::execute()";
589 
590    if ( traceDebug() )
591    {
592       ossimNotify(ossimNotifyLevel_DEBUG) << M << " entered...\n";
593    }
594 
595    // Launch any prep system commands:
596    executePrepCommands();
597 
598    // Get the number of "file*" keywords.
599    ossim_uint32 fileCount = m_kwl->numberOf("file");
600 
601    if ( fileCount )
602    {
603       if ( !m_fileWalker )
604       {
605          m_fileWalker = new ossimFileWalker();
606       }
607 
608       m_fileWalker->setNumberOfThreads( getNumberOfThreads() );
609 
610       // Must set this so we can stop recursion on directory based images.
611       m_fileWalker->setWaitOnDirFlag( true );
612 
613       // This links the file walker back to our "processFile" method.
614       m_fileWalker->setFileProcessor( this );
615 
616       // Wrap in try catch block as excptions can be thrown under the hood.
617       try
618       {
619          // Get the list of files passed to us:
620          std::vector<ossimFilename> files;
621          ossim_uint32 processedFiles = 0;;
622          ossim_uint32 i = 0;
623          while ( processedFiles < fileCount )
624          {
625             ossimString key = FILE_KW;
626             key += ossimString::toString(i);
627             std::string lookup = m_kwl->findKey( key.string() );
628             if ( lookup.size() )
629             {
630                files.push_back( ossimFilename(lookup) );
631                ++processedFiles;
632             }
633 
634             ++i;
635             if ( i > (fileCount + 100) ) break;
636          }
637 
638          //---
639          // If the file count is one and it is not a directory, we will assume
640          // the caller wanted to process that file. So leave the filter list
641          // blank.
642          //---
643          if ( (getOverrideFilteredImagesFlag() == false) && files.size() &&
644               ( (files.size() > 1) || (files[0].isDir() == true) ) )
645          {
646             if ( m_filteredImages.empty() )
647             {
648                initializeDefaultFilterList();
649             }
650             if ( m_fileWalker->getFilteredExtensions().empty() )
651             {
652                m_fileWalker->initializeDefaultFilterList();
653             }
654          }
655 
656          // Process the files:
657          m_fileWalker->walk( files );
658       }
659       catch (const ossimException& e)
660       {
661          ossimNotify(ossimNotifyLevel_WARN)
662             << "Caught exception: " << e.what() << endl;
663          setErrorStatus( ossimErrorCodes::OSSIM_ERROR );
664       }
665 
666    } // if ( fileCount )
667 
668    // Launch any post system commands:
669    executePostCommands();
670 
671    if ( traceDebug() )
672    {
673       ossimNotify(ossimNotifyLevel_DEBUG)
674          << M << " exit status: " << m_errorStatus << std::endl;
675    }
676 
677    // Zero is good, non zero is bad.
678    return m_errorStatus;
679 }
680 
681 //---
682 // This method is called back by the ossimFileWalker::walk method for each file it finds that it
683 // deems can be processed.
684 //---
processFile(const ossimFilename & file)685 void ossimImageUtil::processFile(const ossimFilename& file)
686 {
687    static const char M[] = "ossimImageUtil::processFile";
688    if(traceDebug())
689    {
690       ossimNotify(ossimNotifyLevel_DEBUG)
691          << M << " entered...\n" << "file: " << file << "\n";
692    }
693 
694    bool processFileFlag = true;
695    if ( !getOverrideFilteredImagesFlag() )
696    {
697       processFileFlag = !isFiltered( file );
698    }
699 
700    if ( processFileFlag )
701    {
702       ossimNotify(ossimNotifyLevel_NOTICE) << "Processing file: " << file << std::endl;
703 
704       m_mutex.lock();
705       ossimRefPtr<ossimImageHandler> ih =
706          ossimImageHandlerRegistry::instance()->open(file, true, true);
707       m_mutex.unlock();
708 
709       if ( ih.valid() && !ih->hasError() )
710       {
711          // Check for output directory:
712          if ( m_kwl->hasKey( OUTPUT_DIRECTORY_KW ) )
713          {
714             ossimFilename outputDir;
715             outputDir.string() = m_kwl->findKey( OUTPUT_DIRECTORY_KW );
716 
717             if ( outputDir.exists() && outputDir.isDir() )
718             {
719                ih->setSupplementaryDirectory( outputDir );
720             }
721          }
722 
723          if ( isDirectoryBasedImage( ih.get() ) )
724          {
725             // Tell the walker not to recurse this directory.
726             m_mutex.lock();
727             m_fileWalker->setRecurseFlag(false);
728             m_mutex.unlock();
729          }
730 
731          // Set any reader props:
732          ossimPropertyInterface* pi = dynamic_cast<ossimPropertyInterface*>(ih.get());
733          if ( pi ) setProps(pi);
734 
735          bool consumedHistogramOptions  = false;
736          bool consumedCmmOptions = false;
737 
738          if ( getOutputFileNamesFlag() )
739          {
740             // Simply output the file name of any images we can open:
741             ossimNotify(ossimNotifyLevel_NOTICE) << ih->getFilename().expand();
742          }
743 
744          // Compute/Scan for min, max.  Note the overview sequencer may have computed for us.
745          if ( ( scanForMinMax() || scanForMinMaxNull() ) && !consumedCmmOptions )
746          {
747             computeMinMax( ih );
748          }
749 
750          if ( createOverviews() )
751          {
752             // Skip shape files...
753             if ( ih->getClassName() != "ossimOgrGdalTileSource" )
754             {
755                createOverview(ih, consumedHistogramOptions, consumedCmmOptions);
756             }
757          }
758          if (createThumbnails())
759          {
760                for (ossim_uint32 idx = 0; idx < ih->getNumberOfEntries(); ++idx)
761                {
762                      ih->setCurrentEntry(idx);
763                      if (ih->getNumberOfDecimationLevels() <= 1)
764                      {
765                            ih->setState(0);
766                            ih->openOverview();
767                      }
768                      createThumbnail(ih);
769                }
770          }
771          // Build stand alone histogram.  Note the overview sequencer may have computed for us.
772          if ( hasHistogramOption() && !consumedHistogramOptions)
773          {
774             createHistogram( ih );
775          }
776 
777          // Launch any file system commands.
778          executeFileCommands( file );
779       }
780       else
781       {
782          ossimNotify(ossimNotifyLevel_WARN) << M << "\nCould not open: " << file << std::endl;
783       }
784    }
785    else // Matches: if ( processFileFlag )
786    {
787       ossimNotify(ossimNotifyLevel_NOTICE)
788          << "Filtered file, not processing: " << file << std::endl;
789    }
790 
791    if(traceDebug())
792    {
793       // Since ossimFileWalker is threaded output the file so we know which job exited.
794       ossimNotify(ossimNotifyLevel_DEBUG) << M << "\nfile: " << file << "\nexited...\n";
795    }
796 }
797 
798 // Create overview for image:
createOverview(ossimRefPtr<ossimImageHandler> & ih,bool & consumedHistogramOptions,bool & consumedCmmOptions)799 void ossimImageUtil::createOverview( ossimRefPtr<ossimImageHandler>& ih,
800                                      bool& consumedHistogramOptions,
801                                      bool& consumedCmmOptions )
802 {
803    static const char M[] = "ossimImageUtil::createOverview #1";
804    if(traceDebug())
805    {
806       ossimNotify(ossimNotifyLevel_DEBUG) << M << " entered...\n";
807    }
808 
809    if ( ih.valid() )
810    {
811       // Get the entry list:
812       std::vector<ossim_uint32> entryList;
813       ih->getEntryList(entryList);
814 
815       bool useEntryIndex = false;
816       if ( entryList.size() )
817       {
818          if ( (entryList.size() > 1) || (entryList[0] != 0) ) useEntryIndex = true;
819       }
820 
821       // Create the overview builder:
822       ossimString overviewType;
823       getOverviewType( overviewType.string() );
824       ossimRefPtr<ossimOverviewBuilderBase> ob =
825          ossimOverviewBuilderFactoryRegistry::instance()->createBuilder(overviewType);
826       if ( ob.valid() )
827       {
828          // Set up any overview builder options that don't involve histograms.
829          ossimPropertyInterface* pi = dynamic_cast<ossimPropertyInterface*>( ob.get() );
830          if ( pi ) setProps(pi);
831 
832          ossim_uint32 stopDimension = getOverviewStopDimension();
833          if ( stopDimension ) ob->setOverviewStopDimension(stopDimension);
834 
835          if ( ( scanForMinMax() || scanForMinMaxNull() ) && !hasCmmOption() )
836          {
837             //---
838             // If scan is set and we don't have any min, max, null overrides let the
839             // overview builder scan for min, max.
840             //
841             // If min, max, or null option is set, scan will be performed in
842             // separate function.
843             //---
844             ob->setScanForMinMax( scanForMinMax() );
845             ob->setScanForMinMaxNull( scanForMinMaxNull() );
846             consumedCmmOptions = true;
847          }
848 
849          for(ossim_uint32 idx = 0; idx < entryList.size(); ++idx)
850          {
851             createOverview(ih, ob, entryList[idx], useEntryIndex, consumedHistogramOptions);
852          }
853       }
854       else
855       {
856          ossimNotify(ossimNotifyLevel_WARN)
857             << "ERROR:\nCould not create builder for:  "<< overviewType << std::endl;
858          outputOverviewWriterTypes();
859       }
860    }
861 
862    if(traceDebug())
863    {
864       ossimNotify(ossimNotifyLevel_DEBUG) << M << " exited...\n";
865    }
866 }
867 
868 // Create overview for entry:
createOverview(ossimRefPtr<ossimImageHandler> & ih,ossimRefPtr<ossimOverviewBuilderBase> & ob,ossim_uint32 entry,bool useEntryIndex,bool & consumedHistogramOptions)869 void ossimImageUtil::createOverview(ossimRefPtr<ossimImageHandler>& ih,
870                                     ossimRefPtr<ossimOverviewBuilderBase>& ob,
871                                     ossim_uint32 entry,
872                                     bool useEntryIndex,
873                                     bool& consumedHistogramOptions)
874 {
875    static const char M[] = "ossimImageUtil::createOverview #2";
876    if(traceDebug())
877    {
878       ossimNotify(ossimNotifyLevel_DEBUG) << M << " entered...\n";
879    }
880 
881    if ( ih.valid() && ob.valid() )
882    {
883       if (useEntryIndex)
884       {
885          // Set entry before deriving file name.
886          ih->setCurrentEntry(entry);
887          ossimNotify(ossimNotifyLevel_NOTICE) << "entry number: "<< entry << std::endl;
888       }
889 
890       ossimFilename outputFile =
891          ih->getFilenameWithThisExtension(ossimString(".ovr"), useEntryIndex);
892 
893       if ( rebuildOverviews() )
894       {
895          ih->closeOverview();
896          if ( outputFile.exists() )
897          {
898             outputFile.remove();
899          }
900       }
901 
902       if ( getInternalOverviewsFlag() )
903       {
904          if ( ih->getClassName() == "ossimTiffTileSource")
905          {
906             //---
907             // INTERNAL_OVERVIEWS_FLAG_KW is set to true:
908             // Tiff reader can handle internal overviews.  Set the output file to
909             // input file.  Do it after the above remove so that if there were
910             // external overviews they will get removed.
911             //---
912             outputFile = ih->getFilename();
913          }
914          else
915          {
916             ossimNotify(ossimNotifyLevel_NOTICE)
917                << "Internal overviews not supported for reader type: "
918                <<ih->getClassName()
919                << "\nIgnoring option..."
920                << endl;
921          }
922       }
923 
924       if ( hasRequiredOverview( ih, ob ) == false )
925       {
926          //---
927          // Set create histogram code...
928          //
929          // Notes:
930          // 1) Must put this logic after any removal of external overview file.
931          //
932          // 2) Base file could have built in overviews, e.g. jp2 files.  So the sequensor could
933          //    start at R6 even if there is no external overview file.
934          //
935          // 3) If user want the histogram from R0 the overview builder can do as long as
936          //    ossimImageHandler::getNumberOfDecimationLevels returns 1.  If we are starting
937          //    overview building at R6 then we must do the create histogram in a separate path.
938          //---
939          ossimHistogramMode histoMode = OSSIM_HISTO_MODE_UNKNOWN;
940          if ( createHistogram() ||
941               ( createHistogramR0() && ( ih->getNumberOfDecimationLevels() == 1 ) ) )
942          {
943             histoMode = OSSIM_HISTO_MODE_NORMAL;
944          }
945          else if ( createHistogramFast() )
946          {
947             histoMode = OSSIM_HISTO_MODE_FAST;
948          }
949 
950          if(traceDebug())
951          {
952             ossimNotify(ossimNotifyLevel_DEBUG) << "Histogram mode: " << histoMode << "\n";
953          }
954 
955          if ( histoMode != OSSIM_HISTO_MODE_UNKNOWN )
956          {
957             consumedHistogramOptions = true;
958             ob->setHistogramMode(histoMode);
959 
960             ossimNotify(ossimNotifyLevel_NOTICE)
961                << "Creating overviews with histogram for file: " << ih->getFilename() << std::endl;
962          }
963          else
964          {
965             if ( histoMode != OSSIM_HISTO_MODE_UNKNOWN )
966             {
967                consumedHistogramOptions = false;
968                ossimNotify(ossimNotifyLevel_NOTICE)
969                   << "Creating overviews for file: " << ih->getFilename() << std::endl;
970             }
971          }
972 
973          //---
974          // Set properties, e.g. tile size.  Must be set before the call to
975          // ob->setInputSource(...)
976          //---
977          std::vector< ossimRefPtr<ossimProperty> > propertyList(0);
978          ossimIpt tileSize;
979          if ( getTileSize( tileSize ) == true )
980          {
981             propertyList.push_back(new ossimStringProperty(ossimKeywordNames::OUTPUT_TILE_SIZE_KW,
982             tileSize.toString()));
983             ob->setProperties(propertyList);
984          }
985 
986          ob->setOutputFile(outputFile);
987          ob->setInputSource(ih.get());
988 
989          // Create the overview for this entry in this file:
990          if ( ob->execute() == false )
991          {
992             setErrorStatus( ossimErrorCodes::OSSIM_ERROR );
993             ossimNotify(ossimNotifyLevel_WARN)
994                << "Error returned creating overviews for file: " << ih->getFilename() << std::endl;
995          }
996       }
997       else
998       {
999          consumedHistogramOptions = false;
1000          ossimNotify(ossimNotifyLevel_NOTICE)
1001             << "Image has required reduced resolution data sets." << std::endl;
1002       }
1003    }
1004 
1005    if(traceDebug())
1006    {
1007       ossimNotify(ossimNotifyLevel_DEBUG) << M << " exited...\n";
1008    }
1009 }
createThumbnail(ossimRefPtr<ossimImageHandler> & ih)1010 void ossimImageUtil::createThumbnail(ossimRefPtr<ossimImageHandler> &ih)
1011 {
1012    ossimKeywordlist bandsKeywordList;
1013    bandsKeywordList.add("type", "ossimBandSelector");
1014    bandsKeywordList.add(ossimKeywordNames::BANDS_KW, "default");
1015    ossimRefPtr<ossimImageSource> bs = ossimImageSourceFactoryRegistry::instance()->createImageSource(bandsKeywordList);
1016    if (!bs)
1017       return;
1018    ossimIrect cutRect;
1019    ossimRefPtr<ossimImageRenderer> renderer = new ossimImageRenderer();
1020    ossimRefPtr<ossimScalarRemapper> scalarRemapper = new ossimScalarRemapper();
1021    ossimRefPtr<ossimRectangleCutFilter> cutFilter = new ossimRectangleCutFilter();
1022    ossimRefPtr<ossimImageViewAffineTransform> trans = new ossimImageViewAffineTransform();
1023    ossimDrect bounds = ih->getBoundingRect();
1024    ossim_float64 maxSize = ossim::max(bounds.width(), bounds.height());
1025    ossim_float64 thumbnailSize = getThumbnailSize();
1026    ossim_float64 scale = thumbnailSize / maxSize;
1027    ossimFilename thumbnailFilename = getThumbnailFilename(ih.get());
1028    ossimHistogramRemapper::StretchMode thumbnailStretchType = static_cast<ossimHistogramRemapper::StretchMode> (getThumbnailStretchType());
1029    if (scale > 1.0)
1030    {
1031       scale = 1.0;
1032       cutRect = bounds;
1033    }
1034    else
1035    {
1036       cutRect = bounds * scale;
1037    }
1038    cutFilter->setRectangle(cutRect);
1039    if ((scale < .5) && (ih->getNumberOfDecimationLevels() < 2))
1040    {
1041       return;
1042    }
1043 
1044    trans->scale(scale, scale);
1045    renderer->setImageViewTransform(trans.get());
1046    if (!bs.valid())
1047       return;
1048    bs->connectMyInputTo(ih.get());
1049    bs->initialize();
1050    ossim_uint32 bandCount = bs->getNumberOfInputBands();
1051    if ((bandCount == 2) || (bandCount > 3))
1052    {
1053       ossimBandSelector *tempBs = dynamic_cast<ossimBandSelector *>(bs.get());
1054       if (tempBs)
1055       {
1056          tempBs->setThreeBandRgb();
1057       }
1058    }
1059 
1060    ossimRefPtr<ossimHistogramRemapper> stretch = new ossimHistogramRemapper();
1061    stretch->setStretchMode(thumbnailStretchType);
1062    ossimFilename histogramFilename = ih->createDefaultHistogramFilename();
1063 
1064    //if (!histogramFilename.empty())
1065    //{
1066    //   histogramFile = m_histogramFilename;
1067    // }
1068    stretch->connectMyInputTo(bs.get());
1069    stretch->openHistogram(histogramFilename);
1070    renderer->connectMyInputTo(stretch.get());
1071 
1072    scalarRemapper->connectMyInputTo(renderer.get());
1073    cutFilter->connectMyInputTo(scalarRemapper.get());
1074    ossimKeywordlist writerKwl;
1075    ossimString ext = thumbnailFilename.ext();
1076    ext = ext.downcase();
1077    writerKwl.add("type", "image/" + ext);
1078    writerKwl.add("filename", thumbnailFilename.c_str());
1079    writerKwl.add("create_external_geometry", "false");
1080    if (ext == "png")
1081    {
1082       writerKwl.add("add_alpha_channel", "true");
1083    }
1084    ossimRefPtr<ossimImageFileWriter> writer = ossimImageWriterFactoryRegistry::instance()->createWriter(writerKwl);
1085 
1086    if (writer)
1087    {
1088       writer->connectMyInputTo(cutFilter.get());
1089 
1090       writer->execute();
1091 
1092       writer->disconnect();
1093       writer = 0;
1094    }
1095    scalarRemapper->disconnect();
1096    scalarRemapper = 0;
1097    cutFilter->disconnect();
1098    cutFilter = 0;
1099    renderer->disconnect();
1100    renderer = 0;
1101    stretch->disconnect();
1102    stretch = 0;
1103    bs->disconnect();
1104    bs = 0;
1105 }
1106 
hasRequiredOverview(ossimRefPtr<ossimImageHandler> & ih,ossimRefPtr<ossimOverviewBuilderBase> & ob)1107 bool ossimImageUtil::hasRequiredOverview( ossimRefPtr<ossimImageHandler>& ih,
1108                                           ossimRefPtr<ossimOverviewBuilderBase>& ob )
1109 {
1110    bool result = false;
1111    if ( ih.valid() && ob.valid() && ( getCopyAllFlag() == false ) )
1112    {
1113       if ( ih->getClassName() == "ossimCcfTileSource" )
1114       {
1115          // CCF reader does not use external overviews.
1116          result = true;
1117       }
1118       else
1119       {
1120          // Note we always have one rset
1121          ossim_uint32 required = 1;
1122 
1123          ossim_uint32 startingResLevel      = ih->getNumberOfDecimationLevels();
1124          ossim_uint32 overviewStopDimension = ob->getOverviewStopDimension();
1125 
1126          ossim_uint32 largestImageDimension =
1127             ih->getNumberOfSamples(0) >
1128             ih->getNumberOfLines(0) ?
1129             ih->getNumberOfSamples(0) :
1130             ih->getNumberOfLines(0);
1131 
1132          while(largestImageDimension > overviewStopDimension)
1133          {
1134             largestImageDimension /= 2;
1135             ++required;
1136          }
1137 
1138          if ( startingResLevel >= required )
1139          {
1140             result = true;
1141          }
1142       }
1143    }
1144    return result;
1145 }
1146 
createHistogram(ossimRefPtr<ossimImageHandler> & ih)1147 void ossimImageUtil::createHistogram(ossimRefPtr<ossimImageHandler>& ih)
1148 {
1149    static const char M[] = "ossimImageUtil::createHistogram #1";
1150    if(traceDebug())
1151    {
1152       ossimNotify(ossimNotifyLevel_DEBUG) << M << " entered...\n";
1153    }
1154 
1155    if ( ih.valid() )
1156    {
1157       // Get the entry list:
1158       std::vector<ossim_uint32> entryList;
1159       ih->getEntryList(entryList);
1160 
1161       bool useEntryIndex = false;
1162       if ( entryList.size() )
1163       {
1164          if ( (entryList.size() > 1) || (entryList[0] != 0) ) useEntryIndex = true;
1165       }
1166 
1167       for(ossim_uint32 idx = 0; idx < entryList.size(); ++idx)
1168       {
1169          createHistogram(ih, entryList[idx], useEntryIndex);
1170       }
1171    }
1172 
1173    if(traceDebug())
1174    {
1175       ossimNotify(ossimNotifyLevel_DEBUG) << M << " exited...\n";
1176    }
1177 }
1178 
1179 // Create histogram for entry:
createHistogram(ossimRefPtr<ossimImageHandler> & ih,ossim_uint32 entry,bool useEntryIndex)1180 void ossimImageUtil::createHistogram(ossimRefPtr<ossimImageHandler>& ih,
1181                                      ossim_uint32 entry,
1182                                      bool useEntryIndex)
1183 {
1184    static const char M[] = "ossimImageUtil::createHistogram #2";
1185    if(traceDebug())
1186    {
1187       ossimNotify(ossimNotifyLevel_DEBUG) << M << " entered...\n";
1188    }
1189 
1190    if ( ih.valid() )
1191    {
1192       if (useEntryIndex)
1193       {
1194          // Set entry before deriving file name.
1195          ih->setCurrentEntry(entry);
1196          ossimNotify(ossimNotifyLevel_NOTICE) << "entry number: "<< entry << std::endl;
1197       }
1198 
1199       ossimFilename outputFile =
1200          ih->getFilenameWithThisExtension(ossimString(".his"), useEntryIndex);
1201 
1202       // Only build if needed:
1203       if ( (outputFile.exists() == false) || rebuildHistogram() )
1204       {
1205          ossimNotify(ossimNotifyLevel_NOTICE)
1206             << "Computing histogram for file: " << ih->getFilename() << std::endl;
1207 
1208          // Check handler to see if it's filtering bands.
1209          std::vector<ossim_uint32> originalBandList(0);
1210          if ( ih->isBandSelector() )
1211          {
1212             // Capture for finalize method.
1213             ih->getOutputBandList( originalBandList );
1214 
1215             // Set output list to input.
1216             ih->setOutputToInputBandList();
1217          }
1218 
1219          ossimRefPtr<ossimImageHistogramSource> histoSource = new ossimImageHistogramSource;
1220          ossimRefPtr<ossimHistogramWriter> writer = new ossimHistogramWriter;
1221 
1222          histoSource->setMaxNumberOfRLevels(1); // Currently hard coded...
1223 
1224 #if 0 /* TODO tmp drb */
1225          if( !ossim::isnan(histoMin) )
1226          {
1227             histoSource->setMinValueOverride(histoMin);
1228          }
1229 
1230          if( !ossim::isnan(histoMax) )
1231          {
1232             histoSource->setMaxValueOverride(histoMax);
1233          }
1234 
1235          if(histoBins > 0)
1236          {
1237             histoSource->setNumberOfBinsOverride(histoBins);
1238          }
1239 #endif
1240 
1241          if(traceDebug())
1242          {
1243             ossimNotify(ossimNotifyLevel_DEBUG)
1244                << "Histogram mode: " << getHistogramMode() << "\n";
1245          }
1246 
1247          // Connect histogram source to image handler.
1248          histoSource->setComputationMode( getHistogramMode() );
1249          histoSource->connectMyInputTo(0, ih.get() );
1250          histoSource->enableSource();
1251 
1252          // Connect writer to histogram source.
1253          writer->connectMyInputTo(0, histoSource.get());
1254          writer->setFilename(outputFile);
1255          theStdOutProgress.setFlushStreamFlag(true);
1256          writer->addListener(&theStdOutProgress);
1257 
1258          // Compute...
1259          writer->execute();
1260 
1261          writer=0;
1262 
1263          // Reset the band list.
1264          if ( ih->isBandSelector() && originalBandList.size() )
1265          {
1266             ih->setOutputBandList( originalBandList );
1267          }
1268 
1269       } // Matches: if ( (outputFile.exists() == false) || rebuildHistogram() )
1270 
1271    } // Matches: if ( ih.valid() )
1272 
1273    if(traceDebug())
1274    {
1275       ossimNotify(ossimNotifyLevel_DEBUG) << M << " exited...\n";
1276    }
1277 
1278 } // End: ossimImageUtil::createHistogram #2
1279 
computeMinMax(ossimRefPtr<ossimImageHandler> & ih)1280 void ossimImageUtil::computeMinMax(ossimRefPtr<ossimImageHandler>& ih)
1281 {
1282    static const char M[] = "ossimImageUtil::computeMinMax #1";
1283    if(traceDebug())
1284    {
1285       ossimNotify(ossimNotifyLevel_DEBUG) << M << " entered...\n";
1286    }
1287 
1288    if ( ih.valid() )
1289    {
1290       // Get the entry list:
1291       std::vector<ossim_uint32> entryList;
1292       ih->getEntryList(entryList);
1293 
1294       bool useEntryIndex = false;
1295       if ( entryList.size() )
1296       {
1297          if ( (entryList.size() > 1) || (entryList[0] != 0) ) useEntryIndex = true;
1298       }
1299 
1300       for(ossim_uint32 idx = 0; idx < entryList.size(); ++idx)
1301       {
1302          computeMinMax(ih, entryList[idx], useEntryIndex);
1303       }
1304    }
1305 
1306    if(traceDebug())
1307    {
1308       ossimNotify(ossimNotifyLevel_DEBUG) << M << " exited...\n";
1309    }
1310 
1311 } // End: ossimImageUtil::computeMinMax( ih )
1312 
computeMinMax(ossimRefPtr<ossimImageHandler> & ih,ossim_uint32 entry,bool useEntryIndex)1313 void ossimImageUtil::computeMinMax( ossimRefPtr<ossimImageHandler>& ih,
1314                                     ossim_uint32 entry,
1315                                     bool useEntryIndex )
1316 {
1317    static const char M[] = "ossimImageUtil::computeMinMax #2";
1318    if(traceDebug())
1319    {
1320       ossimNotify(ossimNotifyLevel_DEBUG) << M << " entered...\n";
1321    }
1322 
1323    if ( ih.valid() )
1324    {
1325       // Get any min, max, null overrides;
1326       double maxValue  = ossim::nan();
1327       double minValue  = ossim::nan();
1328       double nullValue = ossim::nan();
1329 
1330       ossimString value = m_kwl->findKey( CMM_MAX_KW );
1331       if ( value.size() )
1332       {
1333          maxValue = value.toDouble();
1334       }
1335 
1336       value = m_kwl->findKey( CMM_MIN_KW );
1337       if ( value.size() )
1338       {
1339          minValue = value.toDouble();
1340       }
1341 
1342       bool hasNull = false;
1343       value = m_kwl->findKey( CMM_NULL_KW );
1344       if ( value.size() )
1345       {
1346          nullValue = value.toDouble();
1347          if ( !ossim::isnan(nullValue) )
1348          {
1349             hasNull = true;
1350          }
1351       }
1352 
1353       // Select the entry.
1354       ih->setCurrentEntry( entry );
1355 
1356       // Build the .omd file name.
1357       ossimFilename omd_file = ih->getFilename();;
1358 
1359       // Check for output directory:
1360       if ( m_kwl->hasKey( OUTPUT_DIRECTORY_KW ) )
1361       {
1362          ossimFilename outputDir;
1363          outputDir.string() = m_kwl->findKey( OUTPUT_DIRECTORY_KW );
1364 
1365          if ( outputDir.exists() && outputDir.isDir() )
1366          {
1367             omd_file = outputDir.dirCat( omd_file.file() );
1368          }
1369       }
1370 
1371       if ( useEntryIndex )
1372       {
1373          ossim_uint32 currentEntry = ih->getCurrentEntry();
1374          omd_file.setExtension("");
1375          omd_file += "_e";
1376          omd_file += ossimString::toString(currentEntry);
1377 
1378          //---
1379          // Note:  Set extension was not used here deliberately to avoid
1380          // messing
1381          // up a MODIS file in hdf format with multiple '.'s in the file
1382          // name.
1383          //---
1384          omd_file += ".omd";
1385       }
1386       else
1387       {
1388          omd_file.setExtension("omd");
1389       }
1390 
1391       ossimRefPtr<ossimImageSourceSequencer> is = new ossimImageSourceSequencer(ih.get());
1392 
1393       //---
1394       // Note: getImageTileWidth/Height will return zero if the image is not
1395       // intenally tiles.
1396       //---
1397       ossimIpt tileWidthHeight( ih->getImageTileWidth(), ih->getImageTileHeight() );
1398       if (!tileWidthHeight.x)
1399       {
1400          //---
1401          // Make the sequencer read entire strips from the image handler
1402          // at a time.  This will speed up access time for strip images
1403          //---
1404          tileWidthHeight.x = ih->getBoundingRect().width();
1405       }
1406       if(!tileWidthHeight.y)
1407       {
1408          tileWidthHeight.y = ih->getTileHeight();
1409       }
1410 
1411       if ( traceDebug() )
1412       {
1413          ossimNotify(ossimNotifyLevel_DEBUG)
1414             << "Sequencer tile size: " << tileWidthHeight << endl;
1415       }
1416 
1417       is->setTileSize(tileWidthHeight);
1418 
1419       //---
1420       // Make arrays of doubles to hold the min/max values.
1421       // Initialize mins to default maxes and maxes to default mins to be
1422       // safe.
1423       //---
1424       ossim_uint32 i; // for numerous iterations...
1425 
1426       const ossimScalarType ST = ih->getOutputScalarType();
1427 
1428       const double DEFAULT_MIN = ossim::defaultMin(ST);
1429       const double DEFAULT_MAX = ossim::defaultMax(ST);
1430 
1431       const ossim_uint32 BANDS = ih->getNumberOfInputBands();
1432 
1433       vector<double> tmin(BANDS);
1434       vector<double> tmax(BANDS);
1435       vector<double> tnull(BANDS);
1436       for (i = 0; i < BANDS; ++i)
1437       {
1438          tmin[i] = DEFAULT_MAX;
1439          tmax[i] = DEFAULT_MIN;
1440 
1441          if ( hasNull )
1442          {
1443             // User passed in with --null option so set here.
1444             tnull[i] = nullValue;
1445          }
1446          else
1447          {
1448             tnull[i] = ih->getNullPixelValue(i);
1449          }
1450       }
1451 
1452       // Scan the image and compute the min and max.
1453       const double TOTAL_TILES = is->getNumberOfTiles();
1454       double tile_count = 0.0;
1455       ossimNotify(ossimNotifyLevel_INFO)
1456          << setiosflags(ios::fixed) << setprecision(0);
1457 
1458       if( (ossim::isnan(minValue) ) || (ossim::isnan(maxValue) ) )
1459       {
1460          ossimRefPtr<ossimImageData> id = is->getNextTile();
1461          while(id.valid())
1462          {
1463             if ( hasNull )
1464             {
1465                // Pass null to image data object so it doesn't get picked up as "min".
1466                id->setNullPix( nullValue );
1467             }
1468             id->computeMinMaxPix(tmin, tmax);
1469             id = is->getNextTile();
1470             ++tile_count;
1471             ossimNotify(ossimNotifyLevel_INFO)
1472                << "\r"  << setw(3)
1473                << (tile_count / TOTAL_TILES * 100.0) << "%"
1474                << flush;
1475          }
1476       }
1477 
1478       if(!ossim::isnan(minValue))
1479       {
1480          std::fill(tmin.begin(), tmin.end(), minValue);
1481       }
1482       if(!ossim::isnan(maxValue))
1483       {
1484          std::fill(tmax.begin(), tmax.end(), maxValue);
1485       }
1486       ossimNotify(ossimNotifyLevel_WARN)
1487          << "\r100%\nFinished..." << endl;
1488 
1489       ossimKeywordlist okwl(omd_file);
1490 
1491       for(i = 0; i < BANDS; ++i)
1492       {
1493          //---
1494          // Check to see if values got assigned.  If not flip to default and
1495          // issue a warning.
1496          //---
1497          if (tmin[i] == DEFAULT_MAX)
1498          {
1499             tmin[i] = DEFAULT_MIN;
1500             ossimNotify(ossimNotifyLevel_WARN)
1501                << "cmm scan for min failed! Using default min."
1502                << std::endl;
1503          }
1504          if (tmax[i] == DEFAULT_MIN)
1505          {
1506             tmax[i] = DEFAULT_MAX;
1507             ossimNotify(ossimNotifyLevel_WARN)
1508                << "cmm scan for max failed! Using default max."
1509                << std::endl;
1510          }
1511 
1512          ossimString band =
1513             ossimString("band")+ossimString::toString(i+1)+".";
1514 
1515          if (tmin[i] == DEFAULT_MAX)
1516          {
1517             tmin[i] = DEFAULT_MIN;
1518          }
1519          // if (tmax[i] == DEFAULT_MIN){}
1520 
1521          okwl.add(band + "min_value", tmin[i], true);
1522          okwl.add(band + "max_value", tmax[i], true);
1523          okwl.add(band + "null_value", tnull[i], true);
1524 
1525          if( traceDebug() )
1526          {
1527             ossimNotify(ossimNotifyLevel_INFO)
1528                << setiosflags(ios::fixed) << setprecision(16)
1529                << "band" << ossimString::toString(i+1) << ".min_value: "
1530                << tmin[i]
1531                << "\nband" << ossimString::toString(i+1) << ".max_value: "
1532                << tmax[i]
1533                << "\nband" << ossimString::toString(i+1) << ".null_value: "
1534                << tnull[i] << endl;
1535          }
1536 
1537       } // End of band loop.
1538 
1539       // Add missing info (number of bands, scalar type) to the .omd file
1540       okwl.add("bytes_per_pixel", ossim::scalarSizeInBytes(ST), true);
1541       okwl.add("number_bands", BANDS, true);
1542       okwl.add("scalar_type", (ossimScalarTypeLut::instance()->getEntryString(ST)), true);
1543 
1544       // Write the file to disk:
1545       okwl.write(omd_file);
1546       ossimNotify(ossimNotifyLevel_INFO)
1547          << "wrote file:  " << omd_file << endl;
1548 
1549       ih->loadMetaData();
1550 
1551    } // Matches: if ( ih.valid() )
1552 
1553    if(traceDebug())
1554    {
1555       ossimNotify(ossimNotifyLevel_DEBUG) << M << " exited...\n";
1556    }
1557 
1558 } // End: ossimImageUtil::computeMinMax( ih, entry, ... )
1559 
usage(ossimArgumentParser & ap)1560 void ossimImageUtil::usage(ossimArgumentParser& ap)
1561 {
1562    // Add global usage options.
1563    ossimInit::instance()->addOptions(ap);
1564 
1565    // Set app name.
1566    ap.getApplicationUsage()->setApplicationName(ap.getApplicationName());
1567 
1568    // Add options.
1569    addArguments(ap);
1570 
1571    // Write usage.
1572    ap.getApplicationUsage()->write(ossimNotify(ossimNotifyLevel_INFO));
1573 
1574    outputOverviewWriterTypes();
1575 
1576    ossimNotify(ossimNotifyLevel_INFO)
1577       << "\nExample commands:\n"
1578 
1579       << "\n// A single image standard tiff overviews, histogram:\n"
1580       << "ossim-preproc -o --ch <file>\n"
1581 
1582       << "\n// A single image with j2k overviews(requires kakadu plugin), histogram:\n"
1583       << "ossim-preproc --ot ossim_kakadu_nitf_j2k --ch <file>\n"
1584       << "\n// j2k, histogram, 4 threads\n"
1585 
1586       << "\n// standard tiff overviews, full histogram, 4 threads:\n"
1587       << "ossim-preproc -r -o --ch --threads 4 <directory_to_walk>\n"
1588 
1589       << "\n// j2k, histogram (fast mode), 4 threads\n"
1590       << "ossim-preproc -r --ot ossim_kakadu_nitf_j2k --chf --threads 4 "
1591       << "<directory_to_walk>\n"
1592 
1593       << "\n// tiff, jpeg compression, histogram, 4 threads\n"
1594       << "ossim-preproc -r --ch --compression-quality 75 --compression-type "
1595       << "jpeg --threads 4 <directory_to_walk>\n"
1596       << "ossim-preproc -r --ch --compression-quality 75 --compression-type "
1597       << "jpeg --threads 4 <directory_to_walk>\n"
1598 
1599       << "\n// Process all the tiffs in a directory feeding \"prep\", \"file\", \"post\" system commands via the --options option which includes indexing file into the omar database via omar-data-mgr app:\n"
1600       << "ossim-preproc --options preproc-options.kwl -r -o --ch *.tif\n"
1601       << "\n// Contents of preproc-options.kwl used in above command:\n"
1602       << "prep.command0: echo start_time: %{date}\n"
1603       << "prep.command0.strf_time_format: %Y%m%d%H%M%S\n"
1604       << "prep.command1: mkdir -p %{date}\n"
1605       << "file.command0: mv %{file_no_ext}.* %{date}/.\n"
1606       << "file.command1: omar-data-mgr -u http://localhost:8080/omar add %{date}/%{basename}\n"
1607       << "post.command0: echo end_time: %{date}\n"
1608       << "post.command0.strf_time_format: %Y%m%d%H%M%S\n"
1609 
1610       << "\nNOTES:\n"
1611       << "\n  --ch  equals --create-histogram"
1612       << "\n  --chf equals --create-histogram-fast"
1613 
1614       << "\n\nExpanded command option variables:\n\n"
1615       << "%{basename}        = filename without path\n"
1616       << "%{basename_no_ext} = filename without path and without extension\n"
1617       << "%{date}            = Expanded to current zulu time. Default format=yyyymmdd\n"
1618       << "                     output format controlled by command0.strf_time_format key.\n"
1619       << "%{dirname}         = path of filename\n"
1620       << "%{file}            = filename being processed\n"
1621       << "%{file_no_ext}     = filename with no extension\n"
1622 
1623       << std::endl;
1624 }
1625 
1626 // Private method:
outputOverviewWriterTypes() const1627 void ossimImageUtil::outputOverviewWriterTypes() const
1628 {
1629    ossimNotify(ossimNotifyLevel_NOTICE)
1630       << "\nValid overview types: " << std::endl;
1631 
1632    std::vector<ossimString> outputType;
1633 
1634    ossimOverviewBuilderFactoryRegistry::instance()->getTypeNameList(outputType);
1635    std::copy(outputType.begin(),
1636              outputType.end(),
1637              std::ostream_iterator<ossimString>(ossimNotify(ossimNotifyLevel_NOTICE), "\t\n"));
1638 }
1639 
1640 // Private method:
isDirectoryBasedImage(const ossimImageHandler * ih) const1641 bool ossimImageUtil::isDirectoryBasedImage(const ossimImageHandler* ih) const
1642 {
1643    bool result = false;
1644    if ( ih )
1645    {
1646       // Get the image handler name.
1647       ossimString imageHandlerName = ih->getClassName();
1648       if ( (imageHandlerName == "ossimAdrgTileSource") ||
1649            (imageHandlerName == "ossimCibCadrgTileSource") )
1650       {
1651          result = true;
1652       }
1653    }
1654    return result;
1655 }
1656 
setCreateOverviewsFlag(bool flag)1657 void ossimImageUtil::setCreateOverviewsFlag( bool flag )
1658 {
1659    addOption( CREATE_OVERVIEWS_KW, ( flag ? TRUE_KW : FALSE_KW ) );
1660 }
1661 
createOverviews() const1662 bool ossimImageUtil::createOverviews() const
1663 {
1664    return  keyIsTrue( CREATE_OVERVIEWS_KW );
1665 }
setCreateThumbnailsFlag(bool flag)1666 void ossimImageUtil::setCreateThumbnailsFlag(bool flag)
1667 {
1668    addOption(CREATE_THUMBNAILS_KW, (flag ? TRUE_KW : FALSE_KW));
1669 }
1670 
createThumbnails() const1671 bool ossimImageUtil::createThumbnails() const
1672 {
1673    return keyIsTrue(CREATE_THUMBNAILS_KW);
1674 }
1675 
setRebuildOverviewsFlag(bool flag)1676 void ossimImageUtil::setRebuildOverviewsFlag( bool flag )
1677 {
1678    addOption( REBUILD_OVERVIEWS_KW, ( flag ? TRUE_KW : FALSE_KW ) );
1679    if ( flag )
1680    {
1681       setCreateOverviewsFlag( true ); // Turn on overview building.
1682    }
1683 }
1684 
rebuildOverviews() const1685 bool ossimImageUtil::rebuildOverviews() const
1686 {
1687    return keyIsTrue( REBUILD_OVERVIEWS_KW );
1688 }
1689 
setRebuildHistogramFlag(bool flag)1690 void ossimImageUtil::setRebuildHistogramFlag( bool flag )
1691 {
1692    addOption( REBUILD_HISTOGRAM_KW, ( flag ? TRUE_KW : FALSE_KW ) );
1693    if ( flag )
1694    {
1695       setCreateHistogramFlag( true ); // Turn on histogram building.
1696    }
1697 }
1698 
rebuildHistogram() const1699 bool ossimImageUtil::rebuildHistogram() const
1700 {
1701    return keyIsTrue( REBUILD_HISTOGRAM_KW );
1702 }
1703 
setScanForMinMax(bool flag)1704 void ossimImageUtil::setScanForMinMax( bool flag )
1705 {
1706    addOption( SCAN_MIN_MAX_KW, ( flag ? TRUE_KW : FALSE_KW ) );
1707 }
1708 
scanForMinMax() const1709 bool ossimImageUtil::scanForMinMax() const
1710 {
1711    return keyIsTrue( SCAN_MIN_MAX_KW );
1712 }
1713 
setScanForMinMaxNull(bool flag)1714 void ossimImageUtil::setScanForMinMaxNull( bool flag )
1715 {
1716    addOption( SCAN_MIN_MAX_NULL_KW, ( flag ? TRUE_KW : FALSE_KW ) );
1717 }
1718 
scanForMinMaxNull() const1719 bool ossimImageUtil::scanForMinMaxNull() const
1720 {
1721    return keyIsTrue( SCAN_MIN_MAX_NULL_KW );
1722 }
1723 
setCompressionQuality(const std::string & quality)1724 void ossimImageUtil::setCompressionQuality( const std::string& quality )
1725 {
1726    if ( quality.size() )
1727    {
1728       std::string key = WRITER_PROP_KW;
1729       key += ossimString::toString( getNextWriterPropIndex() ).string();
1730       std::string value = ossimKeywordNames::COMPRESSION_QUALITY_KW;
1731       value += "=";
1732       value += quality;
1733       addOption( key, value );
1734    }
1735 }
1736 
setCompressionType(const std::string & type)1737 void ossimImageUtil::setCompressionType(const std::string& type)
1738 {
1739    if ( type.size() )
1740    {
1741       std::string key = WRITER_PROP_KW;
1742       key += ossimString::toString( getNextWriterPropIndex() ).string();
1743       std::string value = ossimKeywordNames::COMPRESSION_TYPE_KW;
1744       value += "=";
1745       value += type;
1746       addOption( key, value );
1747    }
1748 }
1749 
setCopyAllFlag(bool flag)1750 void ossimImageUtil::setCopyAllFlag( bool flag )
1751 {
1752    // Add this for hasRequiredOverview method.
1753    std::string key   = COPY_ALL_FLAG_KW;
1754    std::string value = ( flag ? TRUE_KW : FALSE_KW );
1755    addOption( key, value );
1756 
1757    // Add as a writer prop:
1758    key = WRITER_PROP_KW;
1759    key += ossimString::toString( getNextWriterPropIndex() ).string();
1760    value = COPY_ALL_FLAG_KW;
1761    value += "=";
1762    value += ( flag ? TRUE_KW : FALSE_KW );
1763    addOption( key, value );
1764 }
1765 
getCopyAllFlag() const1766 bool ossimImageUtil::getCopyAllFlag() const
1767 {
1768    return keyIsTrue( COPY_ALL_FLAG_KW );
1769 }
1770 
setDumpFilteredImageListFlag(bool flag)1771 void ossimImageUtil::setDumpFilteredImageListFlag( bool flag )
1772 {
1773    std::string key   = DUMP_FILTERED_IMAGES_KW;
1774    std::string value = ( flag ? TRUE_KW : FALSE_KW );
1775    addOption( key, value );
1776 }
1777 
getDumpFilterImagesFlag() const1778 bool ossimImageUtil::getDumpFilterImagesFlag() const
1779 {
1780    return keyIsTrue( DUMP_FILTERED_IMAGES_KW );
1781 }
1782 
setInternalOverviewsFlag(bool flag)1783 void ossimImageUtil::setInternalOverviewsFlag( bool flag )
1784 {
1785    // Add this for hasRequiredOverview method.
1786    std::string key   = INTERNAL_OVERVIEWS_FLAG_KW;
1787    std::string value = ( flag ? TRUE_KW : FALSE_KW );
1788    addOption( key, value );
1789 
1790    // Add as a writer prop:
1791    key = WRITER_PROP_KW;
1792    key += ossimString::toString( getNextWriterPropIndex() ).string();
1793    value = INTERNAL_OVERVIEWS_FLAG_KW;
1794    value += "=";
1795    value += ( flag ? TRUE_KW : FALSE_KW );
1796    addOption( key, value );
1797 }
1798 
getInternalOverviewsFlag() const1799 bool ossimImageUtil::getInternalOverviewsFlag() const
1800 {
1801    return keyIsTrue( INTERNAL_OVERVIEWS_FLAG_KW );
1802 }
1803 
setOutputFileNamesFlag(bool flag)1804 void ossimImageUtil::setOutputFileNamesFlag( bool flag )
1805 {
1806    std::string key   = OUTPUT_FILENAMES_KW;
1807    std::string value = ( flag ? TRUE_KW : FALSE_KW );
1808    addOption( key, value );
1809 }
1810 
getOutputFileNamesFlag() const1811 bool ossimImageUtil::getOutputFileNamesFlag() const
1812 {
1813    return keyIsTrue( OUTPUT_FILENAMES_KW );
1814 }
1815 
setOverrideFilteredImagesFlag(bool flag)1816 void ossimImageUtil::setOverrideFilteredImagesFlag( bool flag )
1817 {
1818    std::string key   = OVERRIDE_FILTERED_IMAGES_KW;
1819    std::string value = ( flag ? TRUE_KW : FALSE_KW );
1820    addOption( key, value );
1821 }
1822 
getOverrideFilteredImagesFlag() const1823 bool ossimImageUtil::getOverrideFilteredImagesFlag() const
1824 {
1825    return keyIsTrue( OVERRIDE_FILTERED_IMAGES_KW );
1826 }
1827 
setOutputDirectory(const std::string & directory)1828 void ossimImageUtil::setOutputDirectory( const std::string& directory )
1829 {
1830    std::string key = OUTPUT_DIRECTORY_KW;
1831    addOption( key, directory );
1832 }
1833 
setOverviewType(const std::string & type)1834 void ossimImageUtil::setOverviewType( const std::string& type )
1835 {
1836    std::string key = OVERVIEW_TYPE_KW;
1837    addOption( key, type );
1838    setCreateOverviewsFlag( true ); // Assume caller wants overviews.
1839 }
1840 
getOverviewType(std::string & type) const1841 void ossimImageUtil::getOverviewType(std::string& type) const
1842 {
1843    std::string lookup = m_kwl->findKey(OVERVIEW_TYPE_KW);
1844    if ( lookup.size() )
1845    {
1846       type = lookup;
1847    }
1848    else
1849    {
1850       type = "ossim_tiff_box"; // default
1851    }
1852 }
1853 
setProps(ossimPropertyInterface * pi) const1854 void ossimImageUtil::setProps(ossimPropertyInterface* pi) const
1855 {
1856    if ( pi )
1857    {
1858       ossimString baseKey;
1859       if ( dynamic_cast<ossimImageHandler*>(pi) )
1860       {
1861          baseKey = READER_PROP_KW;
1862       }
1863       else
1864       {
1865          baseKey = WRITER_PROP_KW;
1866       }
1867 
1868       ossim_uint32 propCount = m_kwl->numberOf( baseKey.c_str() );
1869       if ( propCount )
1870       {
1871          ossim_uint32 foundProps = 0;
1872          ossim_uint32 index = 0;
1873 
1874          // (propCount+100) is to allow for holes like reader_prop0, reader_prop2...
1875          while ( (foundProps < propCount) && (index < (propCount+100) ) )
1876          {
1877             ossimString key = baseKey;
1878             key += ossimString::toString(index);
1879             std::string lookup = m_kwl->findKey( key.string() );
1880             if ( lookup.size() )
1881             {
1882                ossimString value = lookup;
1883                std::vector<ossimString> v = value.split("=");
1884                if (v.size() == 2)
1885                {
1886                   ossimString propertyName  = v[0];
1887                   ossimString propertyValue = v[1];
1888                   ossimRefPtr<ossimProperty> p =
1889                      new ossimStringProperty(propertyName, propertyValue);
1890                   pi->setProperty( p );
1891                }
1892                ++foundProps;
1893             }
1894             ++index;
1895          }
1896       }
1897    }
1898 }
1899 
setOverviewStopDimension(ossim_uint32 dimension)1900 void ossimImageUtil::setOverviewStopDimension( ossim_uint32 dimension )
1901 {
1902    addOption( OVERVIEW_STOP_DIM_KW, dimension );
1903 }
1904 
setOverviewStopDimension(const std::string & dimension)1905 void ossimImageUtil::setOverviewStopDimension( const std::string& dimension )
1906 {
1907    addOption( OVERVIEW_STOP_DIM_KW, dimension );
1908 }
1909 
setTileSize(ossim_uint32 tileSize)1910 void ossimImageUtil::setTileSize( ossim_uint32 tileSize )
1911 {
1912    if ((tileSize % 16) == 0)
1913    {
1914       addOption( TILE_SIZE_KW, tileSize );
1915    }
1916    else
1917    {
1918       ossimNotify(ossimNotifyLevel_NOTICE)
1919          << "ossimImageUtil::setTileSize NOTICE:"
1920          << "\nTile width must be a multiple of 16!"
1921          << std::endl;
1922    }
1923 }
1924 
getTileSize(ossimIpt & tileSize) const1925 bool ossimImageUtil::getTileSize( ossimIpt& tileSize ) const
1926 {
1927    bool result = false;
1928    std::string lookup = m_kwl->findKey( TILE_SIZE_KW );
1929    if ( lookup.size() )
1930    {
1931       ossim_int32 i = ossimString(lookup).toInt32();
1932       if ( (i % 16) == 0 )
1933       {
1934          tileSize.x = i;
1935          tileSize.y = i;
1936          result = true;
1937       }
1938    }
1939    return result;
1940 }
1941 
getOverviewStopDimension() const1942 ossim_uint32 ossimImageUtil::getOverviewStopDimension() const
1943 {
1944    ossim_uint32 result = 0;
1945    std::string lookup = m_kwl->findKey( OVERVIEW_STOP_DIM_KW );
1946    if ( lookup.size() )
1947    {
1948       result = ossimString(lookup).toUInt32();
1949    }
1950    return result;
1951 }
1952 
setCreateHistogramFlag(bool flag)1953 void ossimImageUtil::setCreateHistogramFlag( bool flag )
1954 {
1955    addOption( CREATE_HISTOGRAM_KW, ( flag ? TRUE_KW : FALSE_KW ) );
1956 }
1957 
createHistogram() const1958 bool ossimImageUtil::createHistogram() const
1959 {
1960    return keyIsTrue( CREATE_HISTOGRAM_KW );
1961 }
1962 
setCreateHistogramFastFlag(bool flag)1963 void ossimImageUtil::setCreateHistogramFastFlag( bool flag )
1964 {
1965    addOption( CREATE_HISTOGRAM_FAST_KW, ( flag ? TRUE_KW : FALSE_KW ) );
1966 }
1967 
createHistogramFast() const1968 bool ossimImageUtil::createHistogramFast() const
1969 {
1970    return keyIsTrue( CREATE_HISTOGRAM_FAST_KW );
1971 }
1972 
setCreateHistogramR0Flag(bool flag)1973 void ossimImageUtil::setCreateHistogramR0Flag( bool flag )
1974 {
1975    addOption( CREATE_HISTOGRAM_R0_KW, ( flag ? TRUE_KW : FALSE_KW ) );
1976 }
1977 
createHistogramR0() const1978 bool ossimImageUtil::createHistogramR0() const
1979 {
1980    return keyIsTrue( CREATE_HISTOGRAM_R0_KW );
1981 }
1982 
hasHistogramOption() const1983 bool ossimImageUtil::hasHistogramOption() const
1984 {
1985    return ( createHistogram() || createHistogramFast() || createHistogramR0() );
1986 }
1987 
hasCmmOption() const1988 bool ossimImageUtil::hasCmmOption() const
1989 {
1990    return ( keyIsTrue( CMM_MAX_KW ) || keyIsTrue( CMM_MIN_KW )|| keyIsTrue( CMM_NULL_KW ) );
1991 }
1992 
getHistogramMode() const1993 ossimHistogramMode ossimImageUtil::getHistogramMode() const
1994 {
1995    ossimHistogramMode result = OSSIM_HISTO_MODE_UNKNOWN;
1996    if ( createHistogram() || createHistogramR0() )
1997    {
1998       result = OSSIM_HISTO_MODE_NORMAL;
1999    }
2000    else if ( createHistogramFast() )
2001    {
2002       result = OSSIM_HISTO_MODE_FAST;
2003    }
2004    return result;
2005 }
2006 
setNumberOfThreads(ossim_uint32 threads)2007 void ossimImageUtil::setNumberOfThreads( ossim_uint32 threads )
2008 {
2009    addOption( THREADS_KW, threads );
2010 }
2011 
setNumberOfThreads(const std::string & threads)2012 void ossimImageUtil::setNumberOfThreads( const std::string& threads )
2013 {
2014    addOption( THREADS_KW, threads );
2015 }
2016 
getNumberOfThreads() const2017 ossim_uint32 ossimImageUtil::getNumberOfThreads() const
2018 {
2019    ossim_uint32 result;
2020    std::string lookup = m_kwl->findKey( THREADS_KW );
2021    if ( lookup.size() )
2022    {
2023       result = ossimString(lookup).toUInt32();
2024    }
2025    else
2026    {
2027       result = ossim::getNumberOfThreads();
2028    }
2029    return result;
2030 }
2031 
getNextWriterPropIndex() const2032 ossim_uint32 ossimImageUtil::getNextWriterPropIndex() const
2033 {
2034    ossim_uint32 result = m_kwl->numberOf( WRITER_PROP_KW.c_str() );
2035    if ( result )
2036    {
2037       ossim_uint32 foundProps = 0;
2038       ossim_uint32 index = 0;
2039 
2040       //---
2041       // Loop until we find the last index used for WRITER_PROP_KW.
2042       // (result+100) is to allow for holes like writer_prop0, writer_prop2...
2043       //---
2044       while ( (foundProps < result) && (index < (result+100) ) )
2045       {
2046          ossimString key = WRITER_PROP_KW;
2047          key += ossimString::toString(index);
2048          std::string lookup = m_kwl->findKey( key.string() );
2049          if ( lookup.size() )
2050          {
2051             ++foundProps;
2052          }
2053          ++index;
2054       }
2055       result = index;
2056    }
2057    return result;
2058 }
2059 
getNextReaderPropIndex() const2060 ossim_uint32 ossimImageUtil::getNextReaderPropIndex() const
2061 {
2062    ossim_uint32 result = m_kwl->numberOf( READER_PROP_KW.c_str() );
2063    if ( result )
2064    {
2065       ossim_uint32 foundProps = 0;
2066       ossim_uint32 index = 0;
2067 
2068       //---
2069       // Loop until we find the last index used for WRITER_PROP_KW.
2070       // (result+100) is to allow for holes like reader_prop0, reader_prop2...
2071       //---
2072       while ( (foundProps < result) && (index < (result+100) ) )
2073       {
2074          ossimString key = READER_PROP_KW;
2075          key += ossimString::toString(index);
2076          std::string lookup = m_kwl->findKey( key.string() );
2077          if ( lookup.size() )
2078          {
2079             ++foundProps;
2080          }
2081          ++index;
2082       }
2083       result = index;
2084    }
2085    return result;
2086 }
getThumbnailSize() const2087 ossim_uint32 ossimImageUtil::getThumbnailSize() const
2088 {
2089    ossim_uint32 result;
2090    std::string lookup = m_kwl->findKey(THUMBNAIL_SIZE_KW);
2091    if (lookup.size())
2092    {
2093       result = ossimString(lookup).toUInt32();
2094    }
2095    else
2096    {
2097       result = 256;
2098    }
2099    return result;
2100 }
setThumbnailStretchType(const std::string & value)2101 void ossimImageUtil::setThumbnailStretchType(const std::string &value)
2102 {
2103    addOption(THUMBNAIL_STRETCH_TYPE_KW, value);
2104 }
2105 
getThumbnailStretchType() const2106 int ossimImageUtil::getThumbnailStretchType()const
2107 {
2108    int result = ossimHistogramRemapper::LINEAR_AUTO_MIN_MAX;
2109 
2110    ossimString typeString = m_kwl->findKey(THUMBNAIL_STRETCH_TYPE_KW);
2111 
2112    if (typeString.empty())
2113    {
2114       typeString = "auto-minmax";
2115    }
2116 
2117    typeString = typeString.downcase();
2118 
2119    if ((typeString == "auto-minmax"))
2120    {
2121       result = ossimHistogramRemapper::StretchMode::LINEAR_AUTO_MIN_MAX;
2122    }
2123    else if ((typeString == "auto-percentile"))
2124    {
2125       result = ossimHistogramRemapper::StretchMode::LINEAR_AUTO_PERCENTILE;
2126    }
2127    else if ((typeString == "std-stretch-1") || (typeString == "std-stretch 1"))
2128    {
2129       result = ossimHistogramRemapper::StretchMode::LINEAR_1STD_FROM_MEAN;
2130    }
2131    else if ((typeString == "std-stretch-2") || (typeString == "std-stretch 2"))
2132    {
2133       result = ossimHistogramRemapper::StretchMode::LINEAR_2STD_FROM_MEAN;
2134    }
2135    else if ((typeString == "std-stretch-3") || (typeString == "std-stretch 3"))
2136    {
2137       result = ossimHistogramRemapper::StretchMode::LINEAR_3STD_FROM_MEAN;
2138    }
2139    else if (typeString == "auto-minmax")
2140    {
2141       result = ossimHistogramRemapper::StretchMode::STRETCH_UNKNOWN;
2142    }
2143    return result;
2144 }
2145 
setThumbnailType(const std::string & value)2146 void ossimImageUtil::setThumbnailType(const std::string& value)
2147 {
2148    addOption(THUMBNAIL_TYPE_KW, value);
2149 }
2150 
getThumbnailType() const2151 std::string ossimImageUtil::getThumbnailType() const
2152 {
2153    ossimString typeString = m_kwl->findKey(THUMBNAIL_TYPE_KW);
2154    std::string result = "jpeg";
2155 
2156    typeString = typeString.downcase();
2157 
2158    if(typeString != "png" && typeString != "jpeg")
2159    {
2160       typeString = "jpeg";
2161    }
2162 
2163    result = typeString.string();
2164 
2165    return result;
2166 }
2167 
getThumbnailFilename(ossimImageHandler * ih) const2168 std::string ossimImageUtil::getThumbnailFilename(ossimImageHandler* ih) const
2169 {
2170    ossimFilename thumbnailFilename = ih->getFilenameWithThisExtension("");
2171    std::string thumbnailType = getThumbnailType();
2172    if (thumbnailType == "png")
2173    {
2174       thumbnailFilename = ossimFilename(thumbnailFilename + "thumb.png");
2175    }
2176    else
2177    {
2178       thumbnailFilename = ossimFilename(thumbnailFilename + "thumb.jpg");
2179    }
2180 
2181    return thumbnailFilename.string();
2182 }
2183 
addOption(const std::string & key,ossim_uint32 value)2184 void ossimImageUtil::addOption(const std::string &key, ossim_uint32 value)
2185 {
2186    addOption(key, ossimString::toString(value).string());
2187 }
2188 
addOption(const std::string & key,const std::string & value)2189 void ossimImageUtil::addOption(  const std::string& key, const std::string& value )
2190 {
2191    m_mutex.lock();
2192    if ( m_kwl.valid() )
2193    {
2194       if ( key.size() && value.size() )
2195       {
2196          m_kwl->addPair( key, value );
2197       }
2198    }
2199    m_mutex.unlock();
2200 }
2201 
setErrorStatus(ossim_int32 status)2202 void ossimImageUtil::setErrorStatus( ossim_int32 status )
2203 {
2204    m_mutex.lock();
2205    m_errorStatus = status;
2206    m_mutex.unlock();
2207 }
2208 
isFiltered(const ossimFilename & file) const2209 bool ossimImageUtil::isFiltered(const ossimFilename& file) const
2210 {
2211    bool result = false;
2212    if ( file.size() )
2213    {
2214       // Strip full path to base name.
2215       std::string baseName = file.file().string();
2216       if ( baseName.size() )
2217       {
2218          std::vector<std::string>::const_iterator i = m_filteredImages.begin();
2219          while ( i != m_filteredImages.end() )
2220          {
2221             if ( baseName == (*i) )
2222             {
2223                result = true;
2224                break;
2225             }
2226             ++i;
2227          }
2228       }
2229    }
2230 #if 0 /* Please leave for debug. (drb) */
2231    if(traceDebug())
2232    {
2233       ossimNotify(ossimNotifyLevel_DEBUG)
2234          << "ossimFileWalker::isFiltered file " << (result?"filtered: ":"not filtered: ")
2235          << file << "\n";
2236    }
2237 #endif
2238 
2239    return result;
2240 }
2241 
keyIsTrue(const std::string & key) const2242 bool ossimImageUtil::keyIsTrue( const std::string& key ) const
2243 {
2244    bool result = false;
2245    if ( m_kwl.valid() )
2246    {
2247       std::string value = m_kwl->findKey( key );
2248       if ( value.size() )
2249       {
2250          result = ossimString(value).toBool();
2251       }
2252    }
2253    return result;
2254 }
2255 
getFilteredImages() const2256 const std::vector<std::string>& ossimImageUtil::getFilteredImages() const
2257 {
2258    return m_filteredImages;
2259 }
2260 
getFilteredImages()2261 std::vector<std::string>& ossimImageUtil::getFilteredImages()
2262 {
2263    return m_filteredImages;
2264 }
2265 
initializeDefaultFilterList()2266 void ossimImageUtil::initializeDefaultFilterList()
2267 {
2268    m_mutex.lock();
2269 
2270    // Common images to filter out, put most common first.
2271    m_filteredImages.push_back(std::string("icon.jpg"));
2272    m_filteredImages.push_back(std::string("logo.jpg"));
2273    m_filteredImages.push_back(std::string("preview.jpg"));
2274 
2275    m_mutex.unlock();
2276 }
2277 
dumpFilteredImageList() const2278 void ossimImageUtil::dumpFilteredImageList() const
2279 {
2280    ossimNotify(ossimNotifyLevel_NOTICE) << "Filtered image list:\n";
2281    std::vector<std::string>::const_iterator i = m_filteredImages.begin();
2282    while ( i != m_filteredImages.end() )
2283    {
2284       ossimNotify(ossimNotifyLevel_NOTICE) << (*i) << "\n";
2285       ++i;
2286    }
2287    ossimNotify(ossimNotifyLevel_NOTICE) << std::endl;
2288 }
2289 
executePrepCommands() const2290 void ossimImageUtil::executePrepCommands() const
2291 {
2292    std::string prefix = "prep.";
2293    ossimFilename file = "";
2294    executeCommands( prefix, file );
2295 }
2296 
executeFileCommands(const ossimFilename & file) const2297 void ossimImageUtil::executeFileCommands( const ossimFilename& file ) const
2298 {
2299    std::string prefix = "file.";
2300    executeCommands( prefix, file );
2301 }
2302 
executePostCommands() const2303 void ossimImageUtil::executePostCommands() const
2304 {
2305    std::string prefix = "post.";
2306    ossimFilename file = "";
2307    executeCommands( prefix, file );
2308 }
2309 
executeCommands(const std::string & prefix,const ossimFilename & file) const2310 void ossimImageUtil::executeCommands(
2311    const std::string& prefix, const ossimFilename& file  ) const
2312 {
2313    const std::string BASE_KEY = "command";
2314 
2315    // Get the number of test:
2316    const std::string REG_EXP_STR = prefix + BASE_KEY + std::string("[0-9]+");
2317    const ossim_uint32 NUM_COMMANDS = m_kwl->getNumberOfSubstringKeys(REG_EXP_STR);
2318    if ( NUM_COMMANDS )
2319    {
2320       const ossim_uint32 MAX_INDEX = NUM_COMMANDS + 1000; // for skipage...
2321       ossim_uint32 index = 0;
2322       ossim_uint32 processedIndexes = 0;
2323       std::string commandKey;
2324       ossimString command;
2325 
2326       while ( processedIndexes < MAX_INDEX )
2327       {
2328          commandKey = prefix + BASE_KEY + ossimString::toString( index++ ).string();
2329          command.string() = m_kwl->findKey( commandKey );
2330 
2331          if ( command.size() )
2332          {
2333             substituteCommandString( file, prefix, commandKey, command );
2334 
2335             ossimNotify( ossimNotifyLevel_NOTICE )
2336                << "executing_command: " << command << std::endl;
2337 
2338             // Launch the command:
2339             int status = system( command.c_str() );
2340 
2341             ossimNotify( ossimNotifyLevel_NOTICE )
2342                << "return_status: " << status << std::endl;
2343 
2344             ++processedIndexes;
2345 
2346             if ( processedIndexes == NUM_COMMANDS )
2347             {
2348                break;
2349             }
2350          }
2351       }
2352    }
2353 }
2354 
substituteCommandString(const ossimFilename & file,const std::string & prefix,const std::string & commandKey,ossimString & command) const2355 void ossimImageUtil::substituteCommandString(
2356    const ossimFilename& file,
2357    const std::string& prefix,
2358    const std::string& commandKey,
2359    ossimString& command ) const
2360 {
2361    // Expand any environment vars, e.g. $(env_var_name):
2362    command.expandEnvironmentVariable();
2363 
2364    gsubDate( commandKey, command );
2365 
2366    if ( prefix == "file." )
2367    {
2368       substituteFileStrings( file, command );
2369    }
2370 }
2371 
substituteFileStrings(const ossimFilename & file,ossimString & command) const2372 void ossimImageUtil::substituteFileStrings( const ossimFilename& file,
2373                                             ossimString& command ) const
2374 {
2375    const std::string BASENAME_VARIABLE = "%{basename}";
2376    command.gsub( BASENAME_VARIABLE, file.file().string() );
2377 
2378    const std::string BASENAME_NO_EXT_VARIABLE = "%{basename_no_ext}";
2379    command.gsub( BASENAME_NO_EXT_VARIABLE, file.file().string() );
2380 
2381    const std::string DIRNAME_VARIABLE = "%{dirname}";
2382    command.gsub( DIRNAME_VARIABLE, file.path().string() );
2383 
2384    const std::string FILE_VARIABLE = "%{file}";
2385    command.gsub( FILE_VARIABLE, file.string(), true );
2386 
2387    const std::string FILE_NO_EXT_VARIABLE = "%{file_no_ext}";
2388    command.gsub( FILE_NO_EXT_VARIABLE, file.noExtension().string(), true );
2389 }
2390 
gsubDate(const std::string & commandKey,ossimString & command) const2391 void ossimImageUtil::gsubDate( const std::string& commandKey,
2392                                ossimString& command ) const
2393 {
2394    // Date:
2395    const std::string DATE_VARIABLE = "%{date}";
2396    if ( command.find( DATE_VARIABLE ) )
2397    {
2398       std::string key = ".strf_time_format";
2399       std::string strfTimeFormat = m_kwl->findKey( commandKey, key );
2400       if ( strfTimeFormat.empty() )
2401       {
2402          // yyyymmdd
2403          strfTimeFormat = "%Y%m%d";
2404       }
2405 
2406       //---
2407       // Get the date as a string, e.g 20150411.
2408       // true for gmt time.
2409       //---
2410       std::string date;
2411       ossim::getFormattedTime( strfTimeFormat, true, date );
2412 
2413       if ( date.size() )
2414       {
2415          // Sustitute:
2416          command.gsub( DATE_VARIABLE, date, true );
2417       }
2418    }
2419 }
2420 
2421 
2422