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