/* * GeoTools - The Open Source Java GIS Toolkit * http://geotools.org * * (C) 2008, Open Source Geospatial Foundation (OSGeo) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. */ package org.geotools.utils.imageoverviews; import it.geosolutions.imageio.plugins.tiff.BaselineTIFFTagSet; import it.geosolutions.imageioimpl.plugins.tiff.TIFFImageMetadata; import it.geosolutions.imageioimpl.plugins.tiff.TIFFImageWriter; import it.geosolutions.imageioimpl.plugins.tiff.TIFFImageWriterSpi; import java.awt.RenderingHints; import java.awt.image.renderable.ParameterBlock; import java.io.File; import java.io.FileFilter; import java.io.IOException; import java.util.Iterator; import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; import javax.imageio.IIOImage; import javax.imageio.ImageIO; import javax.imageio.ImageReader; import javax.imageio.ImageTypeSpecifier; import javax.imageio.ImageWriteParam; import javax.imageio.ImageWriter; import javax.imageio.metadata.IIOMetadata; import javax.imageio.stream.ImageInputStream; import javax.imageio.stream.ImageOutputStream; import javax.media.jai.BorderExtender; import javax.media.jai.ImageLayout; import javax.media.jai.InterpolationBicubic; import javax.media.jai.InterpolationBilinear; import javax.media.jai.InterpolationNearest; import javax.media.jai.JAI; import javax.media.jai.RenderedOp; import javax.media.jai.TileCache; import org.apache.commons.cli2.Option; import org.apache.commons.cli2.validation.InvalidArgumentException; import org.apache.commons.cli2.validation.Validator; import org.apache.commons.io.FilenameUtils; import org.apache.commons.io.filefilter.WildcardFileFilter; import org.geotools.image.io.ImageIOExt; import org.geotools.utils.CoverageToolsConstants; import org.geotools.utils.WriteProgressListenerAdapter; import org.geotools.utils.progress.BaseArgumentsManager; import org.geotools.utils.progress.ExceptionEvent; import org.geotools.utils.progress.ProcessingEvent; import org.geotools.utils.progress.ProcessingEventListener; /** * <pre> * Example of usage: * <code> * OverviewsEmbedder -s "/usr/home/tmp" -w *.tiff -t "512,512" -f 32 -n 8 -a nn -c 512 * </code> * <pre> * * <p> * HINT: Take more memory as the 64Mb default by using the following Java Options<BR/> * <code> * -Xmx1024M - Xms512M * </code> * </p> * @author Simone Giannecchini (GeoSolutions) * @author Alessio Fabiani (GeoSolutions) * @since 2.3.x * @version 0.4 * * * * * @source $URL$ */ public class OverviewsEmbedder extends BaseArgumentsManager implements Runnable, ProcessingEventListener { private static final TIFFImageWriterSpi TIFF_IMAGE_WRITER_SPI = new TIFFImageWriterSpi(); public static enum SubsampleAlgorithm{ Nearest, Bilinear, Bicubic, Average, Filtered; // public abstract RenderedImage scale(); } /** * * @author Simone Giannecchini * @since 2.3.x * */ private class OverviewsEmbedderWriteProgressListener extends WriteProgressListenerAdapter { private int lastProgress=0; /* * (non-Javadoc) * * @see it.geosolutions.pyramids.DefaultWriteProgressListener#imageComplete(javax.imageio.ImageWriter) */ public void imageComplete(ImageWriter source) { OverviewsEmbedder.this.fireEvent(new StringBuilder( "Started with writing out overview number ").append( overviewInProcess + 1.0).toString(), (overviewInProcess + 1 / numSteps) * 100.0); } /* * (non-Javadoc) * * @see it.geosolutions.pyramids.DefaultWriteProgressListener#imageProgress(javax.imageio.ImageWriter, * float) */ public void imageProgress(ImageWriter source, float percentageDone) { //trying to reduce the amount of information we spit out since it slows us down final int tempValue=(int)(percentageDone/5.0); if (tempValue > lastProgress) { lastProgress = tempValue; OverviewsEmbedder.this.fireEvent( new StringBuilder("Writing out overview ").append(overviewInProcess + 1) .toString(), (overviewInProcess / numSteps + percentageDone / (100 * numSteps)) * 100.0); } } /* * (non-Javadoc) * * @see it.geosolutions.pyramids.DefaultWriteProgressListener#imageStarted(javax.imageio.ImageWriter, * int) */ public void imageStarted(ImageWriter source, int imageIndex) { OverviewsEmbedder.this.fireEvent(new StringBuilder( "Starting writing out overview number ").append( overviewInProcess + 1).toString(), (overviewInProcess) / (numSteps * 100.0)); } /* * (non-Javadoc) * * @see it.geosolutions.pyramids.DefaultWriteProgressListener#warningOccurred(javax.imageio.ImageWriter, * int, java.lang.String) */ public void warningOccurred(ImageWriter source, int imageIndex, String warning) { OverviewsEmbedder.this.fireEvent(new StringBuilder( "Warning at overview ").append((overviewInProcess + 1)) .toString(), 0); } /* * (non-Javadoc) * * @see it.geosolutions.pyramids.DefaultWriteProgressListener#writeAborted(javax.imageio.ImageWriter) */ public void writeAborted(ImageWriter source) { OverviewsEmbedder.this.fireEvent(new StringBuilder( "Aborted writing process.").toString(), 100.0); } } /** * The default listener for checking the progress of the writing process. */ private final OverviewsEmbedderWriteProgressListener writeProgressListener = new OverviewsEmbedderWriteProgressListener(); private final static String NAME = "OverviewsEmbedder"; /** Program Version */ private final static String VERSION = "0.3"; /** Commons-cli option for the input location. */ private Option locationOpt; /** Commons-cli option for the tile dimension. */ private Option tileDimOpt; /** Commons-cli option for the scale algorithm. */ private Option scaleAlgorithmOpt; /** Commons-cli option for the wild card to use. */ private Option wildcardOpt; /** Commons-cli option for the tile numbe of subsample step to use. */ private Option numStepsOpt; /** Commons-cli option for the scale factor to use. */ private Option scaleFactorOpt; private Option compressionRatioOpt; private Option compressionTypeOpt; /** Tile width. */ private int tileW = -1; /** Tile height. */ private int tileH = -1; /** Scale algorithm. */ private String scaleAlgorithm; /** Logger for this class. */ private final static Logger LOGGER = org.geotools.util.logging.Logging .getLogger(OverviewsEmbedder.class.toString()); /** Default border extender. */ private BorderExtender borderExtender = CoverageToolsConstants.DEFAULT_BORDER_EXTENDER; /** Downsampling step. */ private int downsampleStep; /** Low pass filter. */ private float[] lowPassFilter = CoverageToolsConstants.DEFAULT_KERNEL_GAUSSIAN; /** * The source path. It could point to a single file or to a directory when * we want to embed overwies into a set of files having a certain name. */ private String sourcePath; private String compressionScheme = null; private boolean external=false; private Option externalOpt; private double compressionRatio = CoverageToolsConstants.DEFAULT_COMPRESSION_RATIO; private int numSteps; private String wildcardString = "*.*"; private int fileBeingProcessed; private int overviewInProcess; /** * Simple constructor for a pyramid generator. Use the input string in order * to read an image. * * */ public OverviewsEmbedder() { super(NAME, VERSION); // ///////////////////////////////////////////////////////////////////// // Options for the command line // ///////////////////////////////////////////////////////////////////// locationOpt = optionBuilder .withShortName("s") .withLongName("source") .withArgument( argumentBuilder.withName("source").withMinimum(1) .withMaximum(1).withValidator(new Validator() { public void validate(List args) throws InvalidArgumentException { final int size = args.size(); if (size > 1) throw new InvalidArgumentException("Source can be a single file or directory "); final File source = new File( (String) args.get(0)); if (!source.exists()) throw new InvalidArgumentException( new StringBuilder( "The provided source is invalid! ") .toString()); } }).create()).withDescription( "path where files are located").withRequired(true) .create(); tileDimOpt = optionBuilder.withShortName("t").withLongName( "tiled_dimension").withArgument( argumentBuilder.withName("t").withMinimum(0).withMaximum(1) .create()).withDescription( "tile dimensions as a couple width,height in pixels") .withRequired(false).create(); externalOpt = optionBuilder.withShortName("ext").withLongName( "external_overviews").withArgument( argumentBuilder.withName("extt").withMinimum(0).withMaximum(1) .create()).withDescription( "create external overviews") .withRequired(false).create(); scaleFactorOpt = optionBuilder .withShortName("f") .withLongName("scale_factor") .withArgument( argumentBuilder.withName("f").withMinimum(1) .withMaximum(1).withValidator(new Validator() { public void validate(List args) throws InvalidArgumentException { final int size = args.size(); if (size > 1) throw new InvalidArgumentException( "Only one scale factor at a time can be chosen"); int factor = Integer .parseInt((String) args.get(0)); if (factor <= 0) throw new InvalidArgumentException( new StringBuilder( "The provided scale factor is negative! ") .toString()); if (factor == 1) { LOGGER .warning("The scale factor is 1, program will exit!"); System.exit(0); } } }).create()).withDescription( "integer scale factor") .withRequired(true).create(); wildcardOpt = optionBuilder.withShortName("w").withLongName( "wildcardOpt").withArgument( argumentBuilder.withName("wildcardOpt").withMinimum(0) .withMaximum(1).create()).withDescription( "wildcardOpt to use for selecting files").withRequired(false) .create(); numStepsOpt = optionBuilder.withShortName("n") .withLongName("num_steps").withArgument( argumentBuilder.withName("n").withMinimum(1) .withMaximum(1).withValidator(new Validator() { public void validate(List args) throws InvalidArgumentException { final int size = args.size(); if (size > 1) throw new InvalidArgumentException( "Only one number of step at a time can be chosen"); int steps = Integer .parseInt((String) args.get(0)); if (steps <= 0) throw new InvalidArgumentException( new StringBuilder( "The provided number of step is negative! ") .toString()); } }).create()).withDescription( "integer scale factor").withRequired(true).create(); scaleAlgorithmOpt = optionBuilder .withShortName("a") .withLongName("scaling_algorithm") .withArgument( argumentBuilder.withName("a").withMinimum(0) .withMaximum(1).withValidator(new Validator() { public void validate(List args) throws InvalidArgumentException { final int size = args.size(); if (size > 1) throw new InvalidArgumentException( "Only one scaling algorithm at a time can be chosen"); final SubsampleAlgorithm algorithm=SubsampleAlgorithm.valueOf((String)args.get(0)); if (algorithm==null) throw new InvalidArgumentException( new StringBuilder( "The scaling algorithm ") .append(args.get(0)) .append( " is not supported") .toString()); } }).create()) .withDescription( "name of the scaling algorithm, eeither one of average (a), filtered (f), bilinear (bil), nearest neigbhor (nn)") .withRequired(false).create(); compressionTypeOpt = optionBuilder .withShortName("z") .withLongName("compressionType") .withDescription("compression type.") .withArgument( argumentBuilder.withName("compressionType") .withMinimum(0).withMaximum(1).withValidator( new Validator() { public void validate(List args) throws InvalidArgumentException { final int size = args.size(); if (size > 1) throw new InvalidArgumentException( "Only one scaling algorithm at a time can be chosen"); } }).create()).withRequired(false) .create(); compressionRatioOpt = optionBuilder .withShortName("r") .withLongName("compressionRatio") .withDescription("compression ratio.") .withArgument( argumentBuilder.withName("compressionRatio") .withMinimum(0).withMaximum(1).withValidator( new Validator() { public void validate(List args) throws InvalidArgumentException { final int size = args.size(); if (size > 1) throw new InvalidArgumentException( "Only one scaling algorithm at a time can be chosen"); final String val = (String) args .get(0); final double value = Double .parseDouble(val); if (value <= 0 || value > 1) throw new InvalidArgumentException( "Invalid compressio ratio"); } }).create()).withRequired(false) .create(); addOption(locationOpt); addOption(tileDimOpt); addOption(scaleFactorOpt); addOption(scaleAlgorithmOpt); addOption(numStepsOpt); addOption(wildcardOpt); addOption(compressionTypeOpt); addOption(compressionRatioOpt); addOption(externalOpt); // ///////////////////////////////////////////////////////////////////// // // Help Formatter // // ///////////////////////////////////////////////////////////////////// finishInitialization(); } public int getDownsampleStep() { return downsampleStep; } public void setDownsampleStep(int downsampleWH) { this.downsampleStep = downsampleWH; } public String getSourcePath() { return sourcePath; } public void setSourcePath(String sourcePath) { this.sourcePath = sourcePath; } public int getTileHeight() { return tileH; } public void setTileHeight(int tileHeight) { this.tileH = tileHeight; } public int getTileWidth() { return tileW; } public void setTileWidth(int tileWidth) { this.tileW = tileWidth; } public void setBorderExtender(BorderExtender borderExtender) { this.borderExtender = borderExtender; } public float[] getLowPassFilter() { return lowPassFilter; } public void setLowPassFilter(float[] lowPassFilter) { this.lowPassFilter = lowPassFilter; } public void run() { // did we create a local private tile cache or not? boolean localTileCache= false; // // creating the image to use for the successive // subsampling // TileCache baseTC= JAI.getDefaultInstance().getTileCache(); if(baseTC==null){ localTileCache=true; final long tilecacheSize=super.getTileCacheSize(); baseTC= JAI.createTileCache(); baseTC.setMemoryCapacity(tilecacheSize); baseTC.setMemoryThreshold(0.75f); } // // CHECK INPUT DIRECTORIES/FILES // if(sourcePath==null) { fireEvent("Provided sourcePath is null", 0); return; } // getting an image input stream to the file final File file = new File(sourcePath); final File[] files; int numFiles = 1; StringBuilder message; if(!file.canRead()||!file.exists()) { fireEvent("Provided file "+file.getAbsolutePath()+" cannot be read or does not exist", 0); return; } if (file.isDirectory()) { if(wildcardString==null){ fireEvent("Provided wildcardString is null", 0); return; } final FileFilter fileFilter = new WildcardFileFilter(wildcardString); files = file.listFiles(fileFilter); numFiles = files.length; if (numFiles <= 0) { message = new StringBuilder("No files to process!"); if (LOGGER.isLoggable(Level.FINE)) { LOGGER.fine(message.toString()); } fireEvent(message.toString(), 100); } } else files = new File[] { file }; if(files==null||files.length==0) { fireEvent("Unable to find input files for the provided wildcard "+wildcardString+ " and input path "+sourcePath,0); return; } // // ADDING OVERVIEWS TO ALL FOUND FILES // for (fileBeingProcessed = 0; fileBeingProcessed < numFiles; fileBeingProcessed++) { message = new StringBuilder("Managing file ").append(fileBeingProcessed).append(" of ").append(files[fileBeingProcessed]).append(" files"); if (LOGGER.isLoggable(Level.FINE)) { LOGGER.fine(message.toString()); } fireEvent(message.toString(),((fileBeingProcessed * 100.0) / numFiles)); if (getStopThread()) { message = new StringBuilder("Stopping requested at file ").append(fileBeingProcessed).append(" of ").append(numFiles).append(" files"); if (LOGGER.isLoggable(Level.FINE)) { LOGGER.fine(message.toString()); } fireEvent(message.toString(),((fileBeingProcessed * 100.0) / numFiles)); return; } ImageInputStream stream=null; ImageWriter writer =null; ImageOutputStream streamOut=null; RenderedOp currentImage = null; RenderedOp newImage=null; try{ File localFile=files[fileBeingProcessed]; // // get a stream // stream = ImageIO.createImageInputStream(localFile); if(stream==null) { message = new StringBuilder("Unable to create an input stream for file").append(files[fileBeingProcessed]); if (LOGGER.isLoggable(Level.SEVERE)) { LOGGER.severe(message.toString()); } fireEvent(message.toString(),((fileBeingProcessed * 100.0) / numFiles)); break; } stream.mark(); // // get a reader // final Iterator<ImageReader> it = ImageIO.getImageReaders(stream); if (!it.hasNext()) { message = new StringBuilder("Unable to find a reader for file").append(files[fileBeingProcessed]); if (LOGGER.isLoggable(Level.SEVERE)) { LOGGER.severe(message.toString()); } fireEvent(message.toString(),((fileBeingProcessed * 100.0) / numFiles)); break; } final ImageReader reader = (ImageReader) it.next(); stream.reset(); stream.mark(); // is it a geotiff reader or not? if(!reader.getFormatName().toLowerCase().startsWith("tif")){ if (LOGGER.isLoggable(Level.INFO)) { LOGGER.info("Discarding input file "+files[fileBeingProcessed] + " since it is not a proper tif file."); } continue; } // // set input // reader.setInput(stream); ImageLayout layout = null; // tiling the image if needed int actualTileW = reader.getTileWidth(0); int actualTileH = reader.getTileHeight(0); if (!reader.isImageTiled(0)|| (reader.isImageTiled(0) && (actualTileH != tileH && tileH != -1)|| (actualTileW != tileW && tileW != -1))) { message = new StringBuilder("Retiling image ").append(fileBeingProcessed); if (LOGGER.isLoggable(Level.FINE)) { LOGGER.fine(message.toString()); } fireEvent(message.toString(), ((fileBeingProcessed * 100.0) / numFiles)); layout = Utils.createTiledLayout(tileW, tileH, 0, 0); } stream.reset(); reader.reset(); reader.dispose(); // // output image stream // if(external){ // create a sibling file localFile= new File(localFile.getParent(),FilenameUtils.getBaseName(localFile.getAbsolutePath())+".tif.ovr"); } streamOut = ImageIOExt.createImageOutputStream(null, localFile); if (streamOut == null) { message = new StringBuilder( "Unable to acquire an ImageOutputStream for the file ") .append(files[fileBeingProcessed].toString()); if (LOGGER.isLoggable(Level.SEVERE)) { LOGGER.severe(message.toString()); } fireEvent(message.toString(), ((fileBeingProcessed * 100.0) / numFiles)); break; } // // Preparing to write the set of images. First of all I write // the first image ` // // getting a writer for this reader writer = TIFF_IMAGE_WRITER_SPI.createWriterInstance(); writer.setOutput(streamOut); writer.addIIOWriteProgressListener(writeProgressListener); writer.addIIOWriteWarningListener(writeProgressListener); ImageWriteParam param = writer.getDefaultWriteParam(); // // setting tiling on the first image using writing parameters // if (tileH != -1 & tileW != -1) { param.setTilingMode(ImageWriteParam.MODE_EXPLICIT); param.setTiling(tileW, tileH, 0, 0); } else { param.setTilingMode(ImageWriteParam.MODE_EXPLICIT); param.setTiling(actualTileW, actualTileH, 0, 0); } if (this.compressionScheme != null && !Double.isNaN(compressionRatio)) { param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT); param.setCompressionType(compressionScheme); param.setCompressionQuality((float) this.compressionRatio); } final RenderingHints newHints = new RenderingHints(JAI.KEY_IMAGE_LAYOUT, layout); newHints.add(new RenderingHints(JAI.KEY_TILE_CACHE,baseTC)); // read base image ParameterBlock pbjRead = new ParameterBlock(); pbjRead.add(stream); pbjRead.add(Integer.valueOf(0)); pbjRead.add(Boolean.FALSE); pbjRead.add(Boolean.FALSE); pbjRead.add(Boolean.FALSE); pbjRead.add(null); pbjRead.add(null); pbjRead.add(null); pbjRead.add(null); currentImage = JAI.create("ImageRead", pbjRead,newHints); message = new StringBuilder("Read original image ").append(fileBeingProcessed); if (LOGGER.isLoggable(Level.FINE)) { LOGGER.fine(message.toString()); } fireEvent(message.toString(),((fileBeingProcessed * 100.0) / numFiles)); int i=0; // // OVERVIEWS CYLE // for (overviewInProcess = 0; overviewInProcess < numSteps; overviewInProcess++) { message = new StringBuilder("Subsampling step ").append(overviewInProcess).append(" of image ").append(fileBeingProcessed); if (LOGGER.isLoggable(Level.FINE)) { LOGGER.fine(message.toString()); } fireEvent(message.toString(),((fileBeingProcessed * 100.0) / numFiles)); // paranoiac check if (currentImage.getWidth() / downsampleStep <= 0|| currentImage.getHeight() / downsampleStep <= 0) break; // SCALE // subsampling the input image using the chosen algorithm final SubsampleAlgorithm algorithm=SubsampleAlgorithm.valueOf(scaleAlgorithm); switch (algorithm) { case Average: newImage = Utils.scaleAverage(currentImage,baseTC,downsampleStep,borderExtender); break; case Filtered: newImage = Utils.filteredSubsample(currentImage,baseTC,downsampleStep,lowPassFilter); break; case Bilinear: newImage = Utils.subsample(currentImage,baseTC,new InterpolationBilinear(),downsampleStep,borderExtender); break; case Bicubic: newImage = Utils.subsample(currentImage,baseTC,new InterpolationBicubic(2),downsampleStep,borderExtender); break; case Nearest: newImage = Utils.subsample(currentImage,baseTC, new InterpolationNearest(),downsampleStep,borderExtender); break; default: throw new IllegalArgumentException("Invalid scaling algorithm "+scaleAlgorithm);//cannot get here } //set relevant metadata IIOMetadata imageMetadata = null; if (writer instanceof TIFFImageWriter){ imageMetadata = writer.getDefaultImageMetadata(new ImageTypeSpecifier(newImage), param); if (imageMetadata != null) ((TIFFImageMetadata)imageMetadata).addShortOrLongField(BaselineTIFFTagSet.TAG_NEW_SUBFILE_TYPE, BaselineTIFFTagSet.NEW_SUBFILE_TYPE_REDUCED_RESOLUTION); } // write out if(!external || i>0) writer.writeInsert(-1, new IIOImage(newImage, null, imageMetadata), param); else writer.write(null,new IIOImage(newImage, null, imageMetadata), param); message = new StringBuilder("Step ").append( overviewInProcess).append(" of image ").append( fileBeingProcessed).append(" done!"); if (LOGGER.isLoggable(Level.FINE)) { LOGGER.fine(message.toString()); } fireEvent(message.toString(), ((fileBeingProcessed * 100.0) / numFiles)); // switching images currentImage.dispose(); //dispose old image currentImage = newImage; i++; } // close message message = new StringBuilder("Done with image ") .append(fileBeingProcessed); if (LOGGER.isLoggable(Level.FINE)) { LOGGER.fine(message.toString()); } fireEvent(message.toString(), (((fileBeingProcessed + 1) * 100.0) / numFiles)); }catch (Throwable e) { fireException(e); }finally{ // clean up // clean caches if they are local if(localTileCache&&baseTC!=null) try{ baseTC.flush(); } catch (Exception e) { } // // free everything try { if(streamOut!=null) streamOut.close(); } catch (Throwable e) { if(LOGGER.isLoggable(Level.FINE)) LOGGER.log(Level.FINE,e.getLocalizedMessage(),e); } try { if(writer!=null) writer.dispose(); } catch (Throwable e) { if(LOGGER.isLoggable(Level.FINE)) LOGGER.log(Level.FINE,e.getLocalizedMessage(),e); } try { if (currentImage != null) currentImage.dispose(); } catch (Throwable e) { if (LOGGER.isLoggable(Level.FINE)) LOGGER.log(Level.FINE,e.getLocalizedMessage(),e); } try { if(newImage!=null) newImage.dispose(); } catch (Throwable e) { if (LOGGER.isLoggable(Level.FINE)) LOGGER.log(Level.FINE,e.getLocalizedMessage(),e); } try { if(stream!=null) stream.close(); } catch (Throwable e) { if(LOGGER.isLoggable(Level.FINE)) LOGGER.log(Level.FINE,e.getLocalizedMessage(),e); } } } if (LOGGER.isLoggable(Level.FINE)) LOGGER.fine("Done!!!"); } /* * (non-Javadoc) * * @see it.geosolutions.utils.progress.ProcessingEventListener#getNotification(it.geosolutions.utils.progress.ProcessingEvent) */ public void getNotification(ProcessingEvent event) { LOGGER.info(new StringBuilder("Progress is at ").append( event.getPercentage()).append("\n").append( "attached message is: ").append(event.getMessage()).toString()); } public void exceptionOccurred(ExceptionEvent event) { LOGGER.log(Level.SEVERE, "An error occurred during processing", event .getException()); } public boolean parseArgs(String[] args) { if (!super.parseArgs(args)) return false; // //////////////////////////////////////////////////////////////// // // parsing command line parameters and setting up // Mosaic Index Builder options // // //////////////////////////////////////////////////////////////// sourcePath = (String) getOptionValue(locationOpt); // tile dim if (hasOption(tileDimOpt)) { final String tileDim = (String) getOptionValue(tileDimOpt); final String[] pairs = tileDim.split(","); tileW = Integer.parseInt(pairs[0]); if(pairs.length>1){ tileH = Integer.parseInt(pairs[1]); } else { tileH=tileW; } } // // // // scale factor // // // final String scaleF = (String) getOptionValue(scaleFactorOpt); downsampleStep = Integer.parseInt(scaleF); // // // // wildcard // // // if (hasOption(wildcardOpt)) wildcardString = (String) getOptionValue(wildcardOpt); // // // // external overviews // // // if (hasOption(externalOpt)) external = Boolean.parseBoolean((String)getOptionValue(externalOpt)); // // // // scaling algorithm (default to nearest neighbour) // // // scaleAlgorithm = (String) getOptionValue(scaleAlgorithmOpt); if (scaleAlgorithm == null) scaleAlgorithm = "nn"; // // // // number of steps // // // numSteps = Integer.parseInt((String) getOptionValue(numStepsOpt)); // // // // Compression params // // // // index name if (hasOption(compressionTypeOpt)) { compressionScheme = (String) getOptionValue(compressionTypeOpt); if (compressionScheme == "") compressionScheme = null; } if (hasOption(compressionRatioOpt)) { try { compressionRatio = Double .parseDouble((String) getOptionValue(compressionRatioOpt)); } catch (Exception e) { compressionRatio = Double.NaN; } } return true; } /** * This tool is designed to be used by the command line using this main * class but it can also be used from an GUI by using the setters and * getters. * * @param args * @throws IOException * @throws IllegalArgumentException * @throws InterruptedException */ public static void main(String[] args) throws IllegalArgumentException, IOException, InterruptedException { // creating an overviews embedder final OverviewsEmbedder overviewsEmbedder = new OverviewsEmbedder(); // adding the embedder itself as a listener overviewsEmbedder.addProcessingEventListener(overviewsEmbedder); // parsing input argumentBuilder if (overviewsEmbedder.parseArgs(args)) { // creating a thread to execute the request process, with the // provided priority final Thread t = new Thread(overviewsEmbedder, "OverviewsEmbedder"); t.setPriority(overviewsEmbedder.getPriority()); t.start(); try { t.join(); } catch (InterruptedException e) { LOGGER.log(Level.SEVERE, e.getLocalizedMessage(), e); } } else if (LOGGER.isLoggable(Level.FINE)) LOGGER .fine("Unable to parse command line argumentBuilder, exiting..."); } /** * Sets the wildcar string to use. * * @param wildcardString * the wildcardString to set */ public final void setWildcardString(String wildcardString) { this.wildcardString = wildcardString; } public final double getCompressionRatio() { return compressionRatio; } public final String getCompressionScheme() { return compressionScheme; } public void setCompressionRatio(double compressionRatio) { this.compressionRatio = compressionRatio; } public void setCompressionScheme(String compressionScheme) { this.compressionScheme = compressionScheme; } public String getScaleAlgorithm() { return scaleAlgorithm; } public void setScaleAlgorithm(String scaleAlgorithm) { this.scaleAlgorithm = scaleAlgorithm; } public int getNumSteps() { return numSteps; } public void setNumSteps(int numSteps) { this.numSteps = numSteps; } public OverviewsEmbedderWriteProgressListener getWriteProgressListener() { return writeProgressListener; } public String getWildcardString() { return wildcardString; } }