diff --git a/.gitignore b/.gitignore index a7d24c94..41deb979 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,7 @@ build/ *.eggs dist/ .cache/ +.DS_STORE storm_analysis/test/output/ *__pycache__* diff --git a/storm_analysis/imagej_plugins/dax_file_io/Dax_Reader.jar b/storm_analysis/imagej_plugins/dax_file_io/Dax_Reader.jar new file mode 100644 index 00000000..86c69cd1 Binary files /dev/null and b/storm_analysis/imagej_plugins/dax_file_io/Dax_Reader.jar differ diff --git a/storm_analysis/imagej_plugins/dax_file_io/Dax_Reader.java b/storm_analysis/imagej_plugins/dax_file_io/Dax_Reader.java new file mode 100644 index 00000000..a011443d --- /dev/null +++ b/storm_analysis/imagej_plugins/dax_file_io/Dax_Reader.java @@ -0,0 +1,148 @@ +//ImageJ reader plugin for Zhuang lab .dax files +//Translated from the Python versions in storm-analysis/sa_library and +//based on sample IJ reader/writer plugins by Albert Cardona at +//http://albert.rierol.net/imagej_programming_tutorials.html. +//Evan Heller, 10/2015 + +import java.io.*; +import ij.*; +import ij.io.*; +import ij.plugin.PlugIn; +import ij.plugin.FileInfoVirtualStack; +import java.util.regex.Pattern; +import java.util.regex.Matcher; + +public class Dax_Reader extends ImagePlus implements PlugIn { + + public void run(String arg) { + String path = getPath(arg); + if (null == path) return; + if (!parse(path)) return; + if (null == arg || 0 == arg.trim().length()) this.show(); // was opened by direct call to the plugin + // not via HandleExtraFileTypes which would + // have given a non-null arg. + } + + private String getPath(String arg) { + if (null != arg) { + if (0 == arg.indexOf("http://") || new File(arg).exists()) return arg; + } + // else, ask: + OpenDialog od = new OpenDialog("Choose a .dax file", null); + String dir = od.getDirectory(); + if (null == dir) return null; // dialog was canceled + dir = dir.replace('\\', '/'); // Windows safe + if (!dir.endsWith("/")) dir += "/"; + return dir + od.getFileName(); + } + + private boolean parse(String path) { + File mydax = new File(path); + String dirname = mydax.getParent(); + String filename = mydax.getName(); + if (dirname.length() > 0) dirname += "/"; + + String inf_file = dirname + filename.split("\\.")[0] + ".inf"; + + //Image parameters + int image_height = 256; + int image_width = 256; + int number_frames = 0, scalemax=0, scalemin=0; + boolean bigendian = false; + float lock_target, stage_x = 0, stage_y = 0; + + //Extract the movie information from the associated inf file + Pattern size_re = Pattern.compile("frame dimensions = ([\\d]+) x ([\\d]+)"); + Pattern length_re = Pattern.compile("number of frames = ([\\d]+)"); + Pattern endian_re = Pattern.compile(" (big|little) endian"); + Pattern stagex_re = Pattern.compile("Stage X = ([\\d\\.\\-]+)"); + Pattern stagey_re = Pattern.compile("Stage Y = ([\\d\\.\\-]+)"); + Pattern lock_target_re = Pattern.compile("Lock Target = ([\\d\\.\\-]+)"); + Pattern scalemax_re = Pattern.compile("scalemax = ([\\d\\.\\-]+)"); + Pattern scalemin_re = Pattern.compile("scalemin = ([\\d\\.\\-]+)"); + + try { + BufferedReader br = new BufferedReader(new FileReader(inf_file)); + String line; + Matcher m; + + while ( (line = br.readLine()) != null) { + m = size_re.matcher(line); + if (m.find()) { + image_width = Integer.parseInt(m.group(1)); + image_height = Integer.parseInt(m.group(2)); + } + + m = length_re.matcher(line); + if ( m.find() ) number_frames = Integer.parseInt(m.group(1)); + + m = endian_re.matcher(line); + if ( m.find() ) { + if (m.group(1).equals("big")) bigendian = true; + } + + m = stagex_re.matcher(line); + if ( m.find() ) stage_x = Float.parseFloat(m.group(1)); + + m = stagey_re.matcher(line); + if ( m.find() ) stage_y = Float.parseFloat(m.group(1)); + + m = lock_target_re.matcher(line); + if (m.find() ) lock_target = Float.parseFloat(m.group(1)); + + m = scalemax_re.matcher(line); + if (m.find() ) scalemax = Integer.parseInt(m.group(1)); + + m = scalemin_re.matcher(line); + if ( m.find() ) scalemin = Integer.parseInt(m.group(1)); + } + + br.close(); + + } + catch (IOException e) { + System.err.println("Caught IOException: " + e.getMessage()); + return false; + } + + FileInfo fi = new FileInfo(); + fi.fileType=2; + fi.fileFormat=fi.TIFF; + fi.directory=dirname; + fi.fileName=filename.split("\\.")[0] + ".dax"; + fi.width=image_width; + fi.height=image_height; + fi.nImages=number_frames; + fi.gapBetweenImages = 0; + fi.intelByteOrder = !bigendian; + fi.whiteIsZero = false; + fi.longOffset = fi.offset = 0; + + try { + ImagePlus imp; + + //Open regular stack if small enough; otherwise, virtual + if (number_frames <= 500) { + FileOpener fo = new FileOpener(fi); + imp = fo.open(false); + } + else { + FileInfoVirtualStack fv = new FileInfoVirtualStack(fi, false); + imp = new ImagePlus("",fv); + } + + this.setStack(imp.getTitle(), imp.getStack()); + this.setCalibration(imp.getCalibration()); + Object obinfo = imp.getProperty("Info"); + if (null != obinfo) this.setProperty("Info", obinfo); + this.setFileInfo(imp.getOriginalFileInfo()); + + } + catch (Exception e) { + e.printStackTrace(); + return false; + } + + return true; + } +} diff --git a/storm_analysis/imagej_plugins/dax_file_io/Dax_Writer.jar b/storm_analysis/imagej_plugins/dax_file_io/Dax_Writer.jar new file mode 100644 index 00000000..01b6bf97 Binary files /dev/null and b/storm_analysis/imagej_plugins/dax_file_io/Dax_Writer.jar differ diff --git a/storm_analysis/imagej_plugins/dax_file_io/Dax_Writer.java b/storm_analysis/imagej_plugins/dax_file_io/Dax_Writer.java new file mode 100644 index 00000000..7be46fe8 --- /dev/null +++ b/storm_analysis/imagej_plugins/dax_file_io/Dax_Writer.java @@ -0,0 +1,78 @@ +//ImageJ writer plugin for Zhuang lab .dax files +//Translated from the Python versions in storm-analysis/sa_library and +//based on sample IJ reader/writer plugins by Albert Cardona at +//http://albert.rierol.net/imagej_programming_tutorials.html. +//Evan Heller, 10/2015 + +import java.io.*; +import ij.*; +import ij.io.*; +import ij.plugin.PlugIn; +import ij.process.ImageProcessor; +import ij.process.ImageConverter; + +public class Dax_Writer implements PlugIn { + + public void run(String arg) { + ImagePlus imp = WindowManager.getCurrentImage(); + if (null == imp) return; + SaveDialog sd = new SaveDialog("Save Dax", "untitled", null); + String dir = sd.getDirectory(); + if (null == dir) return; // user canceled dialog + dir = dir.replace('\\', '/'); // Windows safe + if (!dir.endsWith("/")) dir += "/"; + saveDax(imp, dir + sd.getFileName()); + } + + static public void saveDax(ImagePlus imp, String path) { + File file = new File(path); + DataOutputStream dos = null; + + try { + dos = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(file))); + + // read data: + FileInfo fi = imp.getFileInfo(); + String inf_file = path.split("\\.")[0] + ".inf"; + + FileWriter fw = new FileWriter(inf_file); + + //Write a rudimentary .inf file + fw.write("binning = 1 x 1\n"); + fw.write("data type = 16 bit integers (binary, big endian)\n"); + fw.write("frame dimensions = " + fi.width + " x " + fi.height + "\n"); + fw.write("number of frames = " + fi.nImages + "\n"); + fw.write("Lock Target = 0.0\n"); + fw.write("x_start = 1\n"); + fw.write("x_end = " + fi.width + "\n"); + fw.write("y_start = 1\n"); + fw.write("y_end = " + fi.height + "\n"); + fw.flush(); + fw.close(); + + ImageProcessor ip; + + //Covert to 16-bit grayscale for writing to .dax + if (imp.getBitDepth() != 16) { + ImageConverter ic = new ImageConverter(imp); + ic.convertToGray16(); + } + + //Write the data to file + for (int i=0; i=0) + setDimensions(imp.getNChannels(), imp.getNSlices(), imp.getNFrames()); + // copy the image subtitle field ("Label" property) if it exists + if (imp.getProperty("Label")!=null) + setProperty("Label", imp.getProperty("Label")); + if (IJ.getVersion().compareTo("1.41o")>=0) + setOpenAsHyperStack(imp.getOpenAsHyperStack()); + } + + + private Object tryOpen(String directory, String name, String path) { + // set up a stream to read in 132 bytes from the file header + // These can be checked for "magic" values which are diagnostic + // of some image types + InputStream is; + byte[] buf = new byte[132]; + try { + if (0 == path.indexOf("http://")) + is = new java.net.URL(path).openStream(); + else + is = new FileInputStream(path); + is.read(buf, 0, 132); + is.close(); + } + catch (IOException e) { + // couldn't open the file for reading + return null; + } + name = name.toLowerCase(); + width = PLUGIN_NOT_FOUND; + + // Temporarily suppress "plugin not found" errors if LOCI Bio-Formats plugin is installed + if (Menus.getCommands().get("Bio-Formats Importer")!=null && IJ.getVersion().compareTo("1.37u")>=0) + IJ.suppressPluginNotFoundError(); + + // OK now we get to the interesting bit + + // GJ: added Biorad PIC confocal file handler + // ------------------------------------------ + // These make 12345 if you read them as the right kind of short + // and should have this value in every Biorad PIC file + if (buf[54]==57 && buf[55]==48) { + return tryPlugIn("Biorad_Reader", path); + } + // GJ: added Gatan Digital Micrograph DM3 handler + // ---------------------------------------------- + // check if the file ends in .DM3 or .dm3, + // and bytes make an int value of 3 which is the DM3 version number + if (name.endsWith(".dm3") && buf[0]==0 && buf[1]==0 && buf[2]==0 && buf[3]==3) { + return tryPlugIn("DM3_Reader", path); + } + + // IPLab file handler + // Little-endian IPLab files start with "iiii" or "mmmm". + if (name.endsWith(".ipl") || + (buf[0]==105 && buf[1]==105 && buf[2]==105 && buf[3]==105) || + (buf[0]==109 && buf[1]==109 && buf[2]==109 && buf[3]==109)) { + return tryPlugIn("IPLab_Reader", path); + } + + // Packard InstantImager format (.img) handler -> check HERE + // before Analyze check below! + // Check extension and signature bytes KAJ_ + if (name.endsWith(".img") && buf[0]==75 && buf[1]==65 && buf[2]==74 && buf[3]==0) { + return tryPlugIn("InstantImager_Reader", path); + } + + // Analyze format (.img/.hdr) handler + // Opens the file using the Nifti_Reader if it is installed, + // otherwise the Analyze_Reader is used. Note that + // the Analyze_Reader plugin opens and displays the + // image and does not implement the ImagePlus class. + if (name.endsWith(".img") || name.endsWith(".hdr")) { + if (Menus.getCommands().get("NIfTI-Analyze")!=null) + return tryPlugIn("Nifti_Reader", path); + else + return tryPlugIn("Analyze_Reader", path); + } + + // NIFTI format (.nii) handler + if (name.endsWith(".nii") || name.endsWith( ".nii.gz" ) || name.endsWith( ".nii.z" ) ) { + return tryPlugIn("Nifti_Reader", path); + } + + // Image Cytometry Standard (.ics) handler + // http://valelab.ucsf.edu/~nico/IJplugins/Ics_Opener.html + if (name.endsWith(".ics")) { + return tryPlugIn("Ics_Opener", path); + } + + // Princeton Instruments SPE image file (.spe) handler + // http://rsb.info.nih.gov/ij/plugins/spe.html + if (name.endsWith(".spe")) { + return tryPlugIn("OpenSPE_", path); + } + + // Zeiss Confocal LSM 510 image file (.lsm) handler + // http://rsb.info.nih.gov/ij/plugins/lsm-reader.html + if (name.endsWith(".lsm")) { + Object obj = tryPlugIn("LSM_Reader", path); + if (obj==null && Menus.getCommands().get("Show LSMToolbox")!=null) + obj = tryPlugIn("LSM_Toolbox", "file="+path); + return obj; + } + + // BM: added Bruker file handler 29.07.04 + if (name.equals("ser") || name.equals("fid") || name.equals("2rr") || + name.equals("2ii") || name.equals("3rrr") || name.equals("3iii") || + name.equals("2dseq")) { + ij.IJ.showStatus("Opening Bruker " + name + " File"); + return tryPlugIn("BrukerOpener", name + "|" + path); + } + + // AVI: open AVI files using AVI_Reader plugin + if (name.endsWith(".avi")) { + return tryPlugIn("AVI_Reader", path); + } + + // QuickTime: open .mov and .pict files using QT_Movie_Opener plugin + if (name.endsWith(".mov") || name.endsWith(".pict")) { + return tryPlugIn("QT_Movie_Opener", path); + } + + // ZVI file handler + // Little-endian ZVI and Thumbs.db files start with d0 cf 11 e0 + // so we can only look at the extension. + if (name.endsWith(".zvi")) { + return tryPlugIn("ZVI_Reader", path); + } + + // University of North Carolina (UNC) file format handler + // 'magic' numbers are (int) offsets to data structures and + // may change in future releases. + if (name.endsWith(".unc") || (buf[3]==117 && buf[7]==-127 && buf[11]==36 && buf[14]==32 && buf[15]==-127)) { + return tryPlugIn("UNC_Reader", path); + } + + // Amira file handler + // http://wbgn013.biozentrum.uni-wuerzburg.de/ImageJ/amira-io.html + if (buf[0]==0x23 && buf[1]==0x20 && buf[2]==0x41 + && buf[3]==0x6d && buf[4]==0x69 && buf[5]==0x72 + && buf[6]==0x61 && buf[7]==0x4d && buf[8]==0x65 + && buf[9]==0x73&&buf[10]==0x68 && buf[11]==0x20) { + return tryPlugIn("AmiraMeshReader_", path); + } + + // Deltavision file handler + // Open DV files generated on Applied Precision DeltaVision systems + if (name.endsWith(".dv") || name.endsWith(".r3d")) { + return tryPlugIn("Deltavision_Opener", path); + } + + // Albert Cardona: read .mrc files (little endian). + // Documentation at: http://ami.scripps.edu/prtl_data/mrc_specification.htm. + // The parsing of the header is a bare minimum of what could be done. + if (name.endsWith(".mrc")) { + return tryPlugIn("Open_MRC_Leginon", path); + } + + // Albert Cardona: read .dat files from the EMMENU software + if (name.endsWith(".dat") && 1 == buf[1] && 0 == buf[2]) { // 'new format' only + return tryPlugIn("Open_DAT_EMMENU", path); + } + + // Timo Rantalainen and Michael Doube: read Stratec pQCT files. + // File name is IDDDDDDD.MHH, where D is decimal and H is hex. + if (name.matches("[iI]\\d{7}\\.[mM]\\p{XDigit}{2}")) { + return tryPlugIn("org.doube.bonej.pqct.Read_Stratec_File", path); + } + + if (name.endsWith(".dax")) { + return tryPlugIn("Dax_Reader", path); + } + + //Michael Doube: read Scanco ISQ files + //File name is ADDDDDDD.ISQ;D where D is a decimal and A is a letter + try { + String isqMagic=new String(buf,0,16,"UTF-8"); + if (name.matches("[a-z]\\d{7}.isq;\\d+") || isqMagic.equals("CTDATA-HEADER_V1")) + return tryPlugIn("org.bonej.io.ISQReader", path); + } + catch (Exception e) {} + + // Jerome Parent : read .bin from the LynceeTec's software Koala + if (name.endsWith(".bin")) { + return tryPlugIn("Koala_Bin_Reader", path); + } + + // ****************** MODIFY HERE ****************** + // do what ever you have to do to recognise your own file type + // and then call appropriate plugin using the above as models + // e.g.: + + /* + // A. Dent: Added XYZ handler + // ---------------------------------------------- + // check if the file ends in .xyz, and bytes 0 and 1 equal 42 + if (name.endsWith(".xyz") && buf[0]==42 && buf[1]==42) { + // Ok we've identified the file type - now load it + return tryPlugIn("XYZ_Reader", path); + } + */ + + return null; + } + + private ImagePlus openImage(String directory, String name, String path) { + Object o = tryOpen(directory, name, path); + // if an image was returned, assume success + if (o instanceof ImagePlus) return (ImagePlus)o; + + // try opening the file with LOCI Bio-Formats plugin - always check this last! + // Do not call Bio-Formats if File>Import>Image Sequence is opening this file. + if (o==null && (IJ.getVersion().compareTo("1.38j")<0||!IJ.redirectingErrorMessages()) && (new File(path).exists())) { + Object loci = IJ.runPlugIn("loci.plugins.LociImporter", path); + if (loci!=null) { + // plugin exists and was launched + try { + // check whether plugin was successful + Class c = loci.getClass(); + boolean success = c.getField("success").getBoolean(loci); + boolean canceled = c.getField("canceled").getBoolean(loci); + if (success || canceled) { + width = IMAGE_OPENED; + return null; + } + } + catch (Exception exc) { } + } + } + + return null; + + } // openImage + + /** + * Attempts to open the specified path with the given plugin. If the + * plugin extends the ImagePlus class (e.g., BioRad_Reader), set + * extendsImagePlus to true, otherwise (e.g., LSM_Reader) set it to false. + * + * @return A reference to the plugin, if it was successful. + */ + private Object tryPlugIn(String className, String path) { + Object o = IJ.runPlugIn(className, path); + if (o instanceof ImagePlus) { + // plugin extends ImagePlus class + ImagePlus imp = (ImagePlus)o; + if (imp.getWidth()==0) + o = null; // invalid image + else + width = IMAGE_OPENED; // success + } else { + // plugin does not extend ImagePlus; assume success + width = IMAGE_OPENED; + } + return o; + } + + +} diff --git a/storm_analysis/imagej_plugins/dax_file_io/plugins.config b/storm_analysis/imagej_plugins/dax_file_io/plugins.config new file mode 100644 index 00000000..c26b6211 --- /dev/null +++ b/storm_analysis/imagej_plugins/dax_file_io/plugins.config @@ -0,0 +1,2 @@ +File>Save As, "Dax Writer...", Dax_Writer +Plugins, "Dax Writer", Dax_Writer diff --git a/storm_analysis/imagej_plugins/dax_file_io/readme.txt b/storm_analysis/imagej_plugins/dax_file_io/readme.txt new file mode 100644 index 00000000..dc08d567 --- /dev/null +++ b/storm_analysis/imagej_plugins/dax_file_io/readme.txt @@ -0,0 +1,15 @@ +Compiling and using .dax reader/writer plugins with ImageJ + +To use the plugins: +Copy Dax_Reader.jar and Dax_Writer.jar to your Fiji.app/plugins directory. These can be run from the Plugins menu. + + +To add support for using File>Open and dragging and dropping, add the modified HandleExtraFileTypes.class to plugins/IO_*.jar +> jar uf jar uf /Applications/Fiji.app/plugins/IO_-*.jar HandleExtraFileTypes.class + + +To compile plugins from source: +> javac -cp /Applications/Fiji.app/jars/ij-*.jar Dax*.java (substituting for the location of your ImageJ jar). +> jar cf Dax_Reader.jar Dax_Reader* HandleExtraFileTypes.java +> jar cf Dax_Writer.jar Dax_Writer* plugins.config +