/** * SubFile -- read a Granite file; generate a new one that is a subblock * of the input file. The input data can be of any type, * but for now, the output is always float. * Arguments: xfdlfile - input data set * outNameBase - a string to be used as the prefix for the * 2 output files; .bin and .xfdl * bounds - subblock specification * * 22-23 Sept 2011 (derived from SplitData.java and BasicDemo.java) * rdb * ------------------ * History * 26 Sept 11 - rdb added run time option for eliminating meaningless * values. The bunny data uses -1200 to identify coord * positions that seem to be outside the actual data area. * The bunny and other dicomed formatted data shows a * circular data region (such as when viewed by OsirisX). * Map those values to 0. Since I don't know whether -1200 * is just the bunny convention or a more common one, I've * decided to allow the user to specify min and/or max * values; all values outside the range are clamped to * min or max. */ import edu.unh.sdb.common.*; import edu.unh.sdb.datasource.*; import java.io.*; import java.nio.*; import java.util.*; public class SubFile { //----------------- class variables ----------------------------- static String inName = null; static String baseName = null; static int[] boundsArgs = null; static float minVal = Float.MIN_VALUE; static float maxVal = Float.MAX_VALUE; static int numMinClamp = 0; static int numMaxClamp = 0; static float minOver = Float.POSITIVE_INFINITY; static float maxOver = Float.NEGATIVE_INFINITY; static float minUnder = Float.POSITIVE_INFINITY; static float maxUnder = Float.NEGATIVE_INFINITY; static boolean clampValues = false; public static void main(String arg[]) throws FileNotFoundException, IOException { readArgs( arg ); DataSource dataSource = DataSource.create( "input", inName ); dataSource.activate(); System.err.println( "Converting data source " + inName + "\n" + " in bounds " + dataSource.getBounds () ); DataBlock db = getData( dataSource ); System.err.println( " to float, out bounds " + db.getBounds() ); writeFile( db, baseName ); if ( numMinClamp > 0 ) { System.err.println( "minClamps: " + numMinClamp + " from " + minUnder + " to " + maxUnder ); } if ( numMaxClamp > 0 ) { System.err.println( "maxClamps: " + numMaxClamp + " from " + minOver + " to " + maxOver ); } } //------------------- getData ------------------------------- private static DataBlock getData( DataSource inDS ) { int dim = inDS.dim(); ISBounds dsb = inDS.getBounds(); if ( boundsArgs != null ) { int[] lb = new int[ dim ]; int[] ub = new int[ dim ]; if ( boundsArgs.length == dim ) { for ( int i = 0; i < dim; i++ ) { lb[ i ] = 0; ub[ i ] = boundsArgs[ i ] - 1; } dsb = new ISBounds( lb, ub ); } else if ( boundsArgs.length == 2 * dim ) { for ( int i = 0; i < dim; i++ ) { lb[ i ] = boundsArgs[ i ]; ub[ i ] = boundsArgs[ i + 3 ]; } dsb = new ISBounds( lb, ub ); } else { System.err.println( "Error in bounds args: must have " + dim + " bounds or " + (2*dim) + " bounds. " + boundsArgs.length + " found. Using NO subbounds." ); } } DataBlock db = inDS.subblock( dsb ); return db; } //-------------- writeFile ------------------------------------ private static void writeFile( DataBlock block, String base ) throws IOException { ISBounds bnds = block.getBounds(); int lower[] = bnds.copyLowerArray(); int upper[] = bnds.copyUpperArray(); String fileName = base + ".bin"; DataOutputStream out = new DataOutputStream( new FileOutputStream( fileName )); float data[] = block.getFloats(); writeData( out, data ); out.close(); //------------------------------------------------------- // Now write xfdl file //----------------------------- PrintWriter pw = new PrintWriter( new FileOutputStream( base + ".xfdl" )); pw.println( "" ); pw.println( "" ); pw.println( "" ); /** Granite doesn't seem to handle files with non-zero lower bounds, so following output (which should be ok) doesn't work for ( int i = 0; i < lower.length; i++ ) { pw.println( "" ); } *******************************/ // Instead just always have bounds go from 0 to size-1 for ( int i = 0; i < lower.length; i++ ) { pw.println( "" ); } // Now do the fieldNames and types: RecordDescriptor rd = block.getRecordDescriptor (); String[] fieldNames = rd.getFieldNames (); String[] fieldTypes = rd.getFieldTypes (); for (int i = 0; i < fieldNames.length; i++) pw.println ( " " ); // and finish up pw.println( "" ); pw.close(); } //----------------- writeData --------------------------------------- /** * Write the data to the file. */ static void writeData( DataOutputStream out, float[] data ) throws IOException { ByteBuffer bb = ByteBuffer.allocate( data.length * 4 ); FloatBuffer fb = bb.asFloatBuffer(); if ( clampValues ) { // clamp values < min and greater than max for ( int i = 0; i < data.length; i++ ) { if ( data[ i ] < minVal ) { numMinClamp++; if ( data[ i ] > maxUnder ) maxUnder = data[ i ]; if ( data[ i ] < minUnder ) minUnder = data[ i ]; data[i] = minVal; } else if ( data[ i ] > maxVal ) { numMaxClamp++; if ( data[ i ] > maxOver ) maxOver = data[ i ]; if ( data[ i ] < minOver ) minOver = data[ i ]; data[i] = maxVal; } } } fb.put( data ); byte[] bbData = bb.array(); out.write( bbData ); } //---------------------- openDataSource ---------------------------- // a little utility function to read the descriptor file. // private static DataSource openDataSource( String dsName, String fileName ) { DataSource ds = null; try { ds = DataSource.create( dsName, inName ); } catch ( Exception ex ) { System.err.println( "Open error: " + ex.getMessage() ); System.exit( -1 ); } return ds; } //--------------- usage ----------------------------------- static void usage() { PrintStream out = System.out; // should pass in output stream out.println( "Usage: java SubFile infdl outPrefix [-min v1] [-max v2] [ bnds ]" ); out.println( " infdl - xfdl file describing the input DataSource" ); out.println( " outPrefix - prefix for output file names" ); out.println(); out.println( "-min, -max: optional values for clamping input values" ); out.println( " bnds subblock of the DataSource as block input." ); out.println( " bnds must be either n ints or 2n ints where" ); out.println( " n is the dim of DataSource. if n values"); out.println( " specified, they define SIZES of bounds "); out.println( " with 0,0,0 as origin of subblock"); out.println( " if not specified, copies the entire file"); out.println( ""); out.println( "NOTE: output DataSource always float; so no bounds"); out.println( " can be used to convert an int/short ds to floats"); } //-------------- readArgs -------------------------------- // static void readArgs( String[] args ) { if ( args.length == 0 ) { usage(); System.exit( 0 ); } ArrayList intArgs = new ArrayList(); for ( int iarg = 0; iarg < args.length; iarg++ ) { String sarg = args[ iarg ]; if ( inName == null ) // check for file name inName = args[ iarg ]; else if ( baseName == null ) baseName = args[ iarg ]; else if ( sarg.equalsIgnoreCase( "-min" )) { minVal = getArg( args, ++iarg, Float.MIN_VALUE ); clampValues = true; } else if ( sarg.equalsIgnoreCase( "-max" )) { maxVal = getArg( args, ++iarg, Float.MAX_VALUE ); clampValues = true; } else // read bounds arguments intArgs.add( getArg( args, iarg, 0 )); } if ( intArgs.size() > 0 ) { boundsArgs = new int[ intArgs.size() ]; for ( int i = 0; i < intArgs.size(); i++ ) boundsArgs[i] = ((Integer)intArgs.get( i )).intValue(); } } //---------------------- getArg( String[], int, int ) ----------------- /** * This is a utility method for accessing one of the command line * string arguments and converting it to an int. It accepts the * entire array of arguments in String form, an integer indicating * which is to be converted to an int and a default value to be * returned if this argument was not on the command line, or if * the specified String is not a valid integer representation. */ public static int getArg( String[ ] args, int which, int defaultVal ) { try { return Integer.parseInt( args[ which ] ); } catch ( ArrayIndexOutOfBoundsException oob ) { // If there is no args[ which ] element, Java "throws" an exception. // This code "catches" the exception and handles it gracefull. // In this case, it is not an error. The parameter is optional // and there is a specified default value that is returned. } catch ( NumberFormatException nfe ) { // If the string is not a valid representation of an integer // (such as 4Qd3), Integer.parseInt throws a NumberFormatException // Again, this code catches the exception, gives an error message // and uses the default value. System.err.println( "Error: improper command line argument " + which + " = " + args[ which ] + ". It should be an integer; using default value: " + defaultVal ); } return defaultVal; } //---------------------- getArg( String[], int, float ) ----------------- /** * float version of getArg */ public static float getArg( String[ ] args, int which, float defaultVal ) { try { return Float.parseFloat( args[ which ] ); } catch ( ArrayIndexOutOfBoundsException oob ) { } catch ( NumberFormatException nfe ) { System.err.println( "Error: improper command line argument " + which + " = " + args[ which ] + ". It should be an float; using default value: " + defaultVal ); } return defaultVal; } //---------------------- getArg( String[], int, String ) ----------------- /** * String version of getArg */ public static String getArg( String[ ] args, int which, String defaultVal ) { try { return args[ which ]; } catch ( ArrayIndexOutOfBoundsException oob ) { } return defaultVal; } }