001: package it.geosolutions.utils.imagepyramid;
002:
003: import it.geosolutions.utils.coveragetiler.CoverageTiler;
004: import it.geosolutions.utils.imagemosaic.MosaicIndexBuilder;
005: import it.geosolutions.utils.progress.ExceptionEvent;
006: import it.geosolutions.utils.progress.ProcessingEvent;
007: import it.geosolutions.utils.progress.ProcessingEventListener;
008: import it.geosolutions.utils.progress.ProgressManager;
009:
010: import java.awt.RenderingHints;
011: import java.io.BufferedOutputStream;
012: import java.io.BufferedWriter;
013: import java.io.File;
014: import java.io.FileNotFoundException;
015: import java.io.FileOutputStream;
016: import java.io.FileWriter;
017: import java.io.IOException;
018: import java.util.ArrayList;
019: import java.util.List;
020: import java.util.Properties;
021: import java.util.logging.Level;
022: import java.util.logging.Logger;
023:
024: import javax.imageio.ImageIO;
025: import javax.media.jai.BorderExtender;
026: import javax.media.jai.Interpolation;
027: import javax.media.jai.JAI;
028: import javax.media.jai.RecyclingTileFactory;
029: import javax.media.jai.TileCache;
030:
031: import org.apache.commons.cli2.option.DefaultOption;
032: import org.apache.commons.cli2.option.GroupImpl;
033: import org.apache.commons.cli2.util.HelpFormatter;
034: import org.apache.commons.cli2.validation.InvalidArgumentException;
035: import org.apache.commons.cli2.validation.Validator;
036: import org.apache.commons.io.FileUtils;
037: import org.geotools.data.coverage.grid.AbstractGridCoverage2DReader;
038: import org.geotools.data.coverage.grid.AbstractGridFormat;
039: import org.geotools.data.coverage.grid.GridFormatFinder;
040: import org.geotools.geometry.GeneralEnvelope;
041: import org.opengis.coverage.grid.GridRange;
042:
043: /**
044: * Given an original image, builds an image pyramid out of it by combining the
045: * various tiler, mosaic and pyramid layer builder tools.
046: *
047: * <pre>
048: * Example of use:
049: * PyramidBuilder -s "/usr/home/data/home.tif" -f 2 -n 4 -t "25,25" -w
050: * </pre>
051: *
052: * @author Andrea Aime
053: * @since 2.3.x
054: *
055: */
056: public class PyramidBuilder extends ProgressManager implements
057: Runnable, ProcessingEventListener {
058:
059: /**
060: * Default tile cache size.
061: */
062: public final static long DEFAULT_TILE_CHACHE_SIZE = 32 * 1024 * 1024;
063:
064: /**
065: * Default imageio caching behaviour.
066: */
067: public final boolean DEFAULT_IMAGEIO_CACHING_BEHAVIOUR = false;
068:
069: /**
070: * Default thread priority.
071: */
072: public final int DEFAULT_THREAD_PRIORITY = Thread.NORM_PRIORITY;
073:
074: /**
075: * Default interpolation.
076: */
077: public final static Interpolation DEFAULT_INTERPOLATION = Interpolation
078: .getInstance(Interpolation.INTERP_NEAREST);
079:
080: /** Default filter for subsampling averaged. */
081: public final static float[] DEFAULT_KERNEL_GAUSSIAN = new float[] {
082: 0.5F, 1.0F / 3.0F, 0.0F, -1.0F / 12.0F };
083:
084: /**
085: * Default border extender.
086: */
087: public final static BorderExtender DEFAULT_BORDER_EXTENDER = BorderExtender
088: .createInstance(BorderExtender.BORDER_COPY);
089:
090: /** Static immutable ap for scaling algorithms. */
091: private static List scalingAlgorithms;
092: static {
093: scalingAlgorithms = new ArrayList(4);
094: scalingAlgorithms.add("nn");
095: scalingAlgorithms.add("bil");
096: scalingAlgorithms.add("bic");
097: scalingAlgorithms.add("avg");
098: scalingAlgorithms.add("filt");
099: }
100:
101: /** Program Version */
102: private final static String versionNumber = "0.2";
103:
104: /** Commons-cli option for the input location. */
105: private DefaultOption locationOpt;
106:
107: /** Commons-cli option for the output location. */
108: private DefaultOption outputLocationOpt;
109:
110: /** Output folder, defaults to the "pyramid" subfolder */
111: private File outputLocation;
112:
113: /** Commons-cli option for the tile dimension. */
114: private DefaultOption tileDimOpt;
115:
116: /** Commons-cli option for the scale algorithm. */
117: private DefaultOption scaleAlgorithmOpt;
118:
119: /** Commons-cli option for the tile cache size to use. */
120: private DefaultOption tileCacheSizeOpt;
121:
122: /** Commons-cli option for the tile numbe of subsample step to use. */
123: private DefaultOption numStepsOpt;
124:
125: /** Commons-cli option for the scale factor to use. */
126: private DefaultOption scaleFactorOpt;
127:
128: /**
129: * Commons-cli options for overwriting the output layer dirs if already
130: * available
131: */
132: private DefaultOption overwriteOpt;
133:
134: /** Tile width. */
135: private int tileW = -1;
136:
137: /** Tile height. */
138: private int tileH = -1;
139:
140: /** Scale algorithm. */
141: private String scaleAlgorithm;
142:
143: /** Logger for this class. */
144: private final static Logger LOGGER = org.geotools.util.logging.Logging
145: .getLogger(PyramidBuilder.class.toString());
146:
147: /** ImageIO caching behvaiour controller. */
148: private boolean useImageIOCache = DEFAULT_IMAGEIO_CACHING_BEHAVIOUR;
149:
150: /** Default border extender. */
151: private BorderExtender borderExtender = DEFAULT_BORDER_EXTENDER;
152:
153: /** Downsampling step. */
154: private int scaleFactor;
155:
156: /** Default tile cache size. */
157: private long tileCacheSize = DEFAULT_TILE_CHACHE_SIZE;
158:
159: /**
160: * The source path.
161: */
162: private File inputLocation;
163:
164: /**
165: * The name of the output pyramid, will simply be "pyramid" if not set
166: */
167: private String name;
168:
169: /**
170: * Commons-cli option for the pyramid name
171: */
172: private DefaultOption nameOpt;
173:
174: /**
175: *
176: * Interpolation method used througout all the program.
177: *
178: * @TODO make the interpolation method customizable from the user
179: * perpsective.
180: *
181: */
182: private Interpolation interp = DEFAULT_INTERPOLATION;
183:
184: private int numSteps;
185:
186: private boolean exceptionOccurred = false;
187:
188: private boolean overwriteOutputDirs = false;
189:
190: private double currStep = 0;
191:
192: private double totalSteps = 0;
193:
194: /**
195: * Relaunches slave tools progress with the appropriate percentage
196: * corrections
197: */
198: private ProcessingEventListener slaveToolsListener = new ProcessingEventListener() {
199:
200: public void getNotification(ProcessingEvent event) {
201: fireEvent(event.getMessage(), (currStep / totalSteps) * 100
202: + event.getPercentage() / totalSteps);
203: }
204:
205: public void exceptionOccurred(ExceptionEvent event) {
206: fireException(event.getMessage(), event.getPercentage(),
207: event.getException());
208: exceptionOccurred = true;
209: }
210:
211: };
212:
213: private GeneralEnvelope envelope;
214:
215: private double[][] resolutions;
216:
217: /**
218: * Simple constructor for a pyramid generator. Use the input string in order
219: * to read an image.
220: *
221: *
222: */
223: public PyramidBuilder() {
224: // /////////////////////////////////////////////////////////////////////
225: // Options for the command line
226: // /////////////////////////////////////////////////////////////////////
227: helpOpt = optionBuilder.withShortName("h").withShortName("?")
228: .withLongName("helpOpt").withDescription(
229: "print this message.").withRequired(false)
230: .create();
231:
232: versionOpt = optionBuilder.withShortName("v").withLongName(
233: "versionOpt").withDescription("print the versionOpt.")
234: .withRequired(false).create();
235:
236: locationOpt = optionBuilder
237: .withShortName("s")
238: .withLongName("source")
239: .withArgument(
240: arguments.withName("source").withMinimum(1)
241: .withMaximum(1).withValidator(
242: new Validator() {
243:
244: public void validate(
245: List args)
246: throws InvalidArgumentException {
247: final int size = args
248: .size();
249: if (size > 1)
250: throw new InvalidArgumentException(
251: "Source can be a single file or directory ");
252: final File source = new File(
253: (String) args
254: .get(0));
255: if (!source.exists())
256: throw new InvalidArgumentException(
257: new StringBuffer(
258: "The provided source is invalid! ")
259:
260: .toString());
261: }
262:
263: }).create()).withDescription(
264: "path where files are located").withRequired(
265: true)
266: .create();
267:
268: nameOpt = optionBuilder.withShortName("name").withLongName(
269: "pyramid_name").withArgument(
270: arguments.withName("name").withMinimum(0)
271: .withMaximum(1).create()).withDescription(
272: "name for the pyramid property file").withRequired(
273: false).create();
274:
275: tileDimOpt = optionBuilder.withShortName("t").withLongName(
276: "tiled_dimension").withArgument(
277: arguments.withName("t").withMinimum(0).withMaximum(1)
278: .create()).withDescription(
279: "tile dimensions as a couple width,height in pixels")
280: .withRequired(false).create();
281:
282: scaleFactorOpt = optionBuilder.withShortName("f").withLongName(
283: "scale_factor").withArgument(
284: arguments.withName("f").withMinimum(1).withMaximum(1)
285: .withValidator(new Validator() {
286:
287: public void validate(List args)
288: throws InvalidArgumentException {
289: final int size = args.size();
290: if (size > 1)
291: throw new InvalidArgumentException(
292: "Only one scaling algorithm at a time can be chosen");
293: int factor = Integer
294: .parseInt((String) args.get(0));
295: if (factor <= 0)
296: throw new InvalidArgumentException(
297: new StringBuffer(
298: "The provided scale factor is negative! ")
299:
300: .toString());
301: if (factor == 1) {
302: LOGGER
303: .warning("The scale factor is 1, program will exit!");
304: System.exit(0);
305: }
306: }
307:
308: }).create()).withDescription(
309: "integer scale factor").withRequired(true).create();
310:
311: numStepsOpt = optionBuilder.withShortName("n").withLongName(
312: "num_steps").withArgument(
313: arguments.withName("n").withMinimum(1).withMaximum(1)
314: .withValidator(new Validator() {
315:
316: public void validate(List args)
317: throws InvalidArgumentException {
318: final int size = args.size();
319: if (size > 1)
320: throw new InvalidArgumentException(
321: "Only one scaling algorithm at a time can be chosen");
322: int steps = Integer
323: .parseInt((String) args.get(0));
324: if (steps <= 0)
325: throw new InvalidArgumentException(
326: new StringBuffer(
327: "The provided scale factor is negative! ")
328:
329: .toString());
330:
331: }
332:
333: }).create()).withDescription(
334: "integer scale factor").withRequired(true).create();
335:
336: scaleAlgorithmOpt = optionBuilder
337: .withShortName("a")
338: .withLongName("scaling_algorithm")
339: .withArgument(
340: arguments.withName("a").withMinimum(0)
341: .withMaximum(1).withValidator(
342: new Validator() {
343:
344: public void validate(
345: List args)
346: throws InvalidArgumentException {
347: final int size = args
348: .size();
349: if (size > 1)
350: throw new InvalidArgumentException(
351: "Only one scaling algorithm at a time can be chosen");
352: if (!scalingAlgorithms
353: .contains(args
354: .get(0)))
355: throw new InvalidArgumentException(
356: new StringBuffer(
357: "The output format ")
358: .append(
359: args
360: .get(0))
361: .append(
362: " is not permitted")
363: .toString());
364:
365: }
366: }).create())
367: .withDescription(
368: "name of the scaling algorithm, eeither one of average (a), filtered (f), bilinear (bil), nearest neigbhor (nn)")
369: .withRequired(false).create();
370:
371: priorityOpt = optionBuilder.withShortName("p").withLongName(
372: "thread_priority").withArgument(
373: arguments.withName("thread_priority").withMinimum(0)
374: .withMaximum(1).create()).withDescription(
375: "priority for the underlying thread").withRequired(
376: false).create();
377:
378: tileCacheSizeOpt = optionBuilder.withShortName("c")
379: .withLongName("cache_size").withArgument(
380: arguments.withName("c").withMinimum(0)
381: .withMaximum(1).create())
382: .withDescription("tile cache sized")
383: .withRequired(false).create();
384:
385: overwriteOpt = optionBuilder
386: .withShortName("w")
387: .withLongName("overwrite")
388: .withDescription(
389: "completely wipe out existing layer dirs before proceeding.")
390: .withRequired(false).create();
391:
392: cmdOpts.add(locationOpt);
393: cmdOpts.add(tileDimOpt);
394: cmdOpts.add(scaleFactorOpt);
395: cmdOpts.add(scaleAlgorithmOpt);
396: cmdOpts.add(numStepsOpt);
397: cmdOpts.add(priorityOpt);
398: cmdOpts.add(tileCacheSizeOpt);
399: cmdOpts.add(versionOpt);
400: cmdOpts.add(helpOpt);
401: cmdOpts.add(overwriteOpt);
402:
403: optionsGroup = new GroupImpl(cmdOpts, "Options",
404: "All the options", 0, 9);
405:
406: // /////////////////////////////////////////////////////////////////////
407: //
408: // Help Formatter
409: //
410: // /////////////////////////////////////////////////////////////////////
411: final HelpFormatter cmdHlp = new HelpFormatter("| ", " ",
412: " |", 75);
413: cmdHlp.setShellCommand("PyramidBuilder");
414: cmdHlp.setHeader("Help");
415: cmdHlp.setFooter(new StringBuffer(
416: "PyramidBuilder - GeoSolutions S.a.s (C) 2006 - v ")
417: .append(PyramidBuilder.versionNumber).toString());
418: cmdHlp
419: .setDivider("|-------------------------------------------------------------------------|");
420:
421: cmdParser.setGroup(optionsGroup);
422: cmdParser.setHelpOption(helpOpt);
423: cmdParser.setHelpFormatter(cmdHlp);
424: }
425:
426: /**
427: *
428: * This method is a utlity method for setting various JAi wide hints we will
429: * use here and afterwards.
430: *
431: *
432: */
433: private void settingJAIHints() {
434:
435: // //
436: // Imageio caching behaviour in case it is ever needed.
437: // //
438: ImageIO.setUseCache(useImageIOCache);
439:
440: // //
441: //
442: // JAI cache fine tuning
443: //
444: // //
445: final JAI jaiDef = JAI.getDefaultInstance();
446: // setting the tile cache
447: final TileCache cache = jaiDef.getTileCache();
448: cache.setMemoryCapacity(tileCacheSize);
449: // setting JAI wide hints
450: jaiDef.setRenderingHint(JAI.KEY_INTERPOLATION, this .interp);
451: jaiDef.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
452: RenderingHints.VALUE_ANTIALIAS_ON);
453: jaiDef.setRenderingHint(RenderingHints.KEY_RENDERING,
454: RenderingHints.VALUE_RENDER_SPEED);
455: jaiDef.setRenderingHint(JAI.KEY_CACHED_TILE_RECYCLING_ENABLED,
456: Boolean.TRUE);
457: // //
458: //
459: // tile factory and recycler
460: //
461: // //
462: RecyclingTileFactory recyclingFactory = new RecyclingTileFactory();
463: jaiDef.setRenderingHint(JAI.KEY_TILE_FACTORY, recyclingFactory);
464: jaiDef
465: .setRenderingHint(JAI.KEY_TILE_RECYCLER,
466: recyclingFactory);
467:
468: // //
469: //
470: // border extender
471: //
472: // //
473: jaiDef
474: .setRenderingHint(JAI.KEY_BORDER_EXTENDER,
475: borderExtender);
476:
477: }
478:
479: public void run() {
480: // //
481: //
482: // setting JAI wide hints
483: //
484: // //
485: settingJAIHints();
486:
487: // /////////////////////////////////////////////////////////////////////
488: //
489: // Gather reader to compute tile x and y from tile size
490: //
491: // /////////////////////////////////////////////////////////////////////
492:
493: AbstractGridFormat format = (AbstractGridFormat) GridFormatFinder
494: .findFormat(inputLocation);
495: if (format == null) {
496: String message = "Could not find a format for this coverage";
497: fireException(message, 0, new IOException(message));
498: return;
499: }
500: AbstractGridCoverage2DReader inReader = (AbstractGridCoverage2DReader) format
501: .getReader(inputLocation);
502: if (inReader == null) {
503: String message = "Unable to instantiate a reader for this coverage";
504: fireException(message, 0, new IOException(message));
505: return;
506: }
507:
508: envelope = inReader.getOriginalEnvelope();
509: final GridRange range = inReader.getOriginalGridRange();
510: final int numTileX = (int) Math
511: .ceil(range.getLength(0) / tileW);
512: final int numtileY = (int) Math
513: .ceil(range.getLength(1) / tileH);
514: inReader.dispose();
515:
516: // /////////////////////////////////////////////////////////////////////
517: //
518: // Create output directory
519: //
520: // /////////////////////////////////////////////////////////////////////
521:
522: if (!outputLocation.exists())
523: if (!outputLocation.mkdir()) {
524: String message = "Could not create output directory: "
525: + outputLocation;
526: fireException(message, 0, new IOException(message));
527: return;
528: }
529:
530: // /////////////////////////////////////////////////////////////////////
531: //
532: // Compute total steps and set current one so that slave tools progress
533: // event percentages can be corrected to represent the global progress
534: //
535: // //////////////////////////////////////////////////////////////////////
536:
537: totalSteps = (numSteps + 1) * 2;
538: currStep = 1;
539:
540: // /////////////////////////////////////////////////////////////////////
541: //
542: // Set up initial level using the coverage tiler
543: //
544: // /////////////////////////////////////////////////////////////////////
545:
546: File outputDir = new File(outputLocation, "0");
547: if (!checkLayerDir(outputDir))
548: return;
549:
550: // create first tiled set
551: resolutions = new double[2][numSteps + 1];
552: tileInput(numTileX, numtileY, outputDir);
553: if (exceptionOccurred)
554: return;
555: currStep++;
556:
557: // mosaic it
558: double[] resolution = mosaicLevel(0);
559: resolutions[0][0] = resolution[0];
560: resolutions[1][0] = resolution[1];
561: if (exceptionOccurred)
562: return;
563: currStep++;
564:
565: // /////////////////////////////////////////////////////////////////////
566: //
567: // Now do create a new level, and mosaic it, up to the final level
568: //
569: // /////////////////////////////////////////////////////////////////////
570: int currLevel = scaleFactor;
571: int prevLevel = 0;
572: for (int step = 0; step < numSteps; step++) {
573: // check output dir
574: File prevLevelDirectory = new File(outputLocation, String
575: .valueOf(prevLevel));
576: File currLevelDirectory = new File(outputLocation, String
577: .valueOf(currLevel));
578: if (!checkLayerDir(currLevelDirectory))
579: return;
580:
581: // create next tiled set
582: buildNewLayer(prevLevelDirectory, currLevelDirectory);
583: if (exceptionOccurred)
584: return;
585: currStep++;
586:
587: // mosaic it
588: resolution = mosaicLevel(currLevel);
589: resolutions[0][step + 1] = resolution[0];
590: resolutions[1][step + 1] = resolution[1];
591: if (exceptionOccurred)
592: return;
593: currStep++;
594:
595: // switch to next resolution level
596: prevLevel = currLevel;
597: currLevel *= scaleFactor;
598: }
599:
600: // /////////////////////////////////////////////////////////////////////
601: //
602: // Finally, build the property file
603: //
604: // /////////////////////////////////////////////////////////////////////
605:
606: fireEvent("Creating final properties file ", 99.9);
607: createPropertiesFiles();
608: if (!exceptionOccurred)
609: fireEvent("Done!!!", 100);
610: }
611:
612: private boolean checkLayerDir(File outputDir) {
613: if (!outputDir.exists())
614: return true;
615: if (!overwriteOutputDirs) {
616: fireException(new IOException("Layer directory "
617: + outputDir
618: + " already exist. Use -w to force its deletion"));
619: return false;
620: }
621: try {
622: FileUtils.deleteDirectory(outputDir);
623: } catch (IOException e) {
624: fireException(e);
625: return false;
626: }
627: return true;
628: }
629:
630: private void tileInput(final int numTileX, final int numtileY,
631: File outputDir) {
632: CoverageTiler tiler = new CoverageTiler();
633: tiler.addProcessingEventListener(slaveToolsListener);
634: tiler.setInputLocation(inputLocation);
635: tiler.setOutputLocation(outputDir);
636: tiler.setNumTileX(numTileX);
637: tiler.setNumTileY(numtileY);
638: tiler.run();
639: tiler.removeAllProcessingEventListeners();
640: }
641:
642: private void buildNewLayer(File prevLevelDirectory,
643: File currLevelDirectory) {
644: PyramidLayerBuilder layerBuilder = new PyramidLayerBuilder();
645: layerBuilder.addProcessingEventListener(slaveToolsListener);
646: layerBuilder.setInputLocation(new File(prevLevelDirectory, name
647: + ".shp"));
648: layerBuilder.setOutputLocation(currLevelDirectory);
649: layerBuilder.setScaleAlgorithm(scaleAlgorithm);
650: layerBuilder.setScaleFactor(scaleFactor);
651: layerBuilder.setTileH(tileH);
652: layerBuilder.setTileW(tileW);
653: layerBuilder.run();
654: layerBuilder.removeAllProcessingEventListeners();
655: }
656:
657: private double[] mosaicLevel(int level) {
658: MosaicIndexBuilder builder = new MosaicIndexBuilder();
659: builder.addProcessingEventListener(slaveToolsListener);
660: builder.setLocationPath(new File(outputLocation, String
661: .valueOf(level)).getAbsolutePath());
662: builder.setIndexName(name);
663: builder.run();
664: builder.removeAllProcessingEventListeners();
665: return new double[] { builder.getResolutionX(),
666: builder.getResolutionY() };
667: }
668:
669: /**
670: * @param envelope
671: * @param doneSomething
672: */
673: private void createPropertiesFiles() {
674: // envelope
675: final Properties properties = new Properties();
676: properties.setProperty("Envelope2D", new StringBuffer(Double
677: .toString(envelope.getMinimum(0))).append(",").append(
678: Double.toString(envelope.getMinimum(1))).append(" ")
679: .append(Double.toString(envelope.getMaximum(0)))
680: .append(",").append(
681: Double.toString(envelope.getMaximum(1)))
682: .toString());
683: properties.setProperty("LevelsNum", Integer
684: .toString(numSteps + 1));
685: final StringBuffer levels = new StringBuffer();
686: final StringBuffer levelDirs = new StringBuffer();
687: for (int i = 0; i < numSteps + 1; i++) {
688: levels.append(Double.toString(resolutions[0][i])).append(
689: ",").append(Double.toString(resolutions[1][i]));
690: levelDirs.append(i == 0 ? "0" : Integer.toString((int) Math
691: .pow(scaleFactor, i)));
692: if (i < numSteps) {
693: levels.append(" ");
694: levelDirs.append(" ");
695: }
696: }
697: properties.setProperty("Levels", levels.toString());
698: properties.setProperty("LevelsDirs", levelDirs.toString());
699: properties.setProperty("Name", name);
700: try {
701: properties.store(new BufferedOutputStream(
702: new FileOutputStream(new File(outputLocation, name
703: + ".properties"))), "");
704:
705: // //
706: // Creating PRJ file
707: // //
708: File prjFile = new File(outputLocation, name + ".prj");
709: BufferedWriter out = new BufferedWriter(new FileWriter(
710: prjFile));
711: out.write(envelope.getCoordinateReferenceSystem().toWKT());
712: out.close();
713: } catch (FileNotFoundException e) {
714: fireException(e);
715: } catch (IOException e) {
716: fireException(e);
717: }
718: }
719:
720: public void getNotification(ProcessingEvent event) {
721: LOGGER.info(new StringBuffer("Progress is at ").append(
722: event.getPercentage()).append("\n").append(
723: "attached message is: ").append(event.getMessage())
724: .toString());
725: }
726:
727: public void exceptionOccurred(ExceptionEvent event) {
728: LOGGER.log(Level.SEVERE, "An error occurred during processing",
729: event.getException());
730: }
731:
732: private boolean parseArgs(String[] args) {
733: cmdLine = cmdParser.parseAndHelp(args);
734: if (cmdLine != null && cmdLine.hasOption(versionOpt)) {
735: LOGGER
736: .fine(new StringBuffer(
737: "OverviewsEmbedder - GeoSolutions S.a.s (C) 2006 - v")
738: .append(PyramidBuilder.versionNumber)
739: .toString());
740: System.exit(1);
741:
742: } else if (cmdLine != null) {
743: // ////////////////////////////////////////////////////////////////
744: //
745: // parsing command line parameters and setting up
746: // Pyramid Builder options
747: //
748: // ////////////////////////////////////////////////////////////////
749: inputLocation = new File((String) cmdLine
750: .getValue(locationOpt));
751:
752: // output files' directory
753: if (cmdLine.hasOption(outputLocationOpt))
754: outputLocation = new File((String) cmdLine
755: .getValue(outputLocationOpt));
756: else
757: outputLocation = new File(
758: inputLocation.getParentFile(), "pyramid");
759:
760: // output file name
761: if (cmdLine.hasOption(nameOpt))
762: name = (String) cmdLine.getValue(nameOpt);
763: else
764: name = "pyramid";
765:
766: // shall we overwrite the output dirs?
767: overwriteOutputDirs = cmdLine.hasOption(overwriteOpt);
768:
769: // tile dim
770: if (cmdLine.hasOption(tileDimOpt)) {
771: final String tileDim = (String) cmdLine
772: .getValue(tileDimOpt);
773: final String[] pairs = tileDim.split(",");
774: tileW = Integer.parseInt(pairs[0]);
775: tileH = Integer.parseInt(pairs[1]);
776: }
777: // //
778: //
779: // scale factor
780: //
781: // //
782: final String scaleF = (String) cmdLine
783: .getValue(scaleFactorOpt);
784: scaleFactor = Integer.parseInt(scaleF);
785:
786: // //
787: //
788: // scaling algorithm (default to nearest neighbour)
789: //
790: // //
791: scaleAlgorithm = (String) cmdLine
792: .getValue(scaleAlgorithmOpt);
793: if (scaleAlgorithm == null)
794: scaleAlgorithm = "nn";
795:
796: // //
797: //
798: // number of steps
799: //
800: // //
801: numSteps = Integer.parseInt((String) cmdLine
802: .getValue(numStepsOpt));
803:
804: // //
805: //
806: // Thread priority
807: //
808: // //
809: // index name
810: if (cmdLine.hasOption(priorityOpt))
811: priority = Integer.parseInt((String) cmdLine
812: .getValue(priorityOpt));
813:
814: // //
815: //
816: // Tile cache size
817: //
818: // //
819: // index name
820: if (cmdLine.hasOption(tileCacheSizeOpt)) {
821: tileCacheSize = Integer.parseInt((String) cmdLine
822: .getValue(tileCacheSizeOpt));
823:
824: }
825: return true;
826:
827: }
828: return false;
829:
830: }
831:
832: /**
833: * This tool is designed to be used by the command line using this main
834: * class but it can also be used from an GUI by using the setters and
835: * getters.
836: *
837: * @param args
838: * @throws IOException
839: * @throws IllegalArgumentException
840: * @throws InterruptedException
841: */
842: public static void main(String[] args)
843: throws IllegalArgumentException, IOException,
844: InterruptedException {
845:
846: // creating an overviews embedder
847: final PyramidBuilder builder = new PyramidBuilder();
848: // adding the embedder itself as a listener
849: builder.addProcessingEventListener(builder);
850: // parsing input arguments
851: if (builder.parseArgs(args)) {
852: // creating a thread to execute the request process, with the
853: // provided priority
854: final Thread t = new Thread(builder, "PyramidBuilder");
855: t.setPriority(builder.priority);
856: t.start();
857: try {
858: t.join();
859: } catch (InterruptedException e) {
860: LOGGER.log(Level.SEVERE, e.getLocalizedMessage(), e);
861: }
862:
863: } else if (LOGGER.isLoggable(Level.FINE))
864: LOGGER
865: .fine("Unable to parse command line arguments, exiting...");
866:
867: }
868: }
|