Macro to batch convert DM3 to TIFF

imagej
metadata
macro

#1

Hi,
I have been working a little bit on a macro to batch convert DM3 to TIFF. This is what it does:

  • Gets as input a folder (and sub folders) and a export file type.
  • Batch converts ALL the DM3 to the file type.
    • The Images obtain a Scale bar which is always around 1/3 of the width of the image, with nice numbers, such as 1, 2, 5, 10, 20, 50, 100, 200, 500…
    • The diffractions obtain the same scale bar but with 1/nm instead of nm units.
    • The EELS obtain NO scale bar. Instead, they are saved as 2 different documents:
      • A 2-column text file, with the Energy and counts
      • A image which lets you see how the spectrum looks like when digging in the folder, BUT just for that. This image is not calibrated nor has good quality, is just for easy seeking.

This macro is made up with pieces of several other macros/plugins, and I hope all of them are correctly refereed on it.

The macro requires CSI Spectrum reader, because it is the only way I found to get the data from the DM3.

If anyone has time and wants to dig in the macro, to find possible improvements, I would be happy.

Right now it makes what I need, it is a little bit slow (needs like 0.3s for each image) but it is enought for me.

I do not know how to attach files, so I just post it here:

// This macro batch processes .dm3 images saved with Gatan software
// for Transmission Electron Microscope (TEM) imaging. It adds scale bar to each image
// and converts them from .dm3 to different types of image
// the diffractions obtain a scalebar with 1/nm , and the EELS are saved
//as crappy image for track, and 2-column txt file
// global author: Oliver Dieste, 21.01.2016, JRC-ITU (Karlsruhe)

// last modification: 27.01.2016, 14:24

//REQUIRES CSI DM3 Reader plugin http://code.google.com/p/cornell-spectrum-imager/wiki/Home


// partially copied from: Amirhossein Khalajhedayati, 12/10/2013, University of California Irvine, USA
// Some other parts of this code were obtained from multiple resources on the web. 

requires("1.33n");
dir = getDirectory("Choose a directory that contains dm3 files");
//i removed the output place, I prefer to have the tif where the dm3 are

format = getFormat();
start = getTime();
setBatchMode(true);
print("\\Clear")
//start the process: lets find the images in the folder and SUBFOLDERS
find(dir);


//print a count of the time
print("Processing time:   " + (getTime() - start) / 1000 + " Seconds");

//END
/////////////////////////////////////////

function find(dir) {
print("Entering "+dir);
    //showStatus("enter " + dir);
    //this function iterates in the sub-folders to find the dm3 files
    // copied from the ListFilesRecursively macro
    list = getFileList(dir);

    for (i = 0; i < list.length; i++) {
        if (endsWith(list[i], "/")) {
	//if you find a dir, go deep on it
           // print("Entering "+dir+list[i]);
	find("" + dir + list[i]);
        } 
	else if (endsWith(list[i], "dm3")) {
            //if you find a dm3, convert it!
            convert_image(list[i], dir);
           showProgress(i, list.length);
        }
    }
}

function convert_image(file_dm3, dir_dm3) {
imagestart=getTime();
>
   //partially borrowed from ser2tiff plugin
   //by J Kaelber at National University of Singapore on 20 July 2012
	
   //this function converts the image
    path = dir_dm3 + file_dm3;
	outputDirectory = dir_dm3;
    outFile = outputDirectory + file_dm3;
	IJ.redirectErrorMessages();

    open(path);
    getPixelSize(unit, pixelWidth, pixelHeight);

    //we check if it is EELS with the signal value
    eels = getTag("ImageTags.Meta Data.Signal");

   //if it is not EELS
    if (eels != " EELS") {
        //now we check if image or diffraction
        modo = getTag("ImageTags.Microscope Info.Operation Mode");
        if (modo != " IMAGING") {
            //for diffraction change scale unit
            run("Set Scale...", "unit=1/nm");
	}
        //for both images and diffraction create a scale bar
        //and save the images
        crea_bar(pixelWidth);
        // windows does not like tiff with 16bit. 
  
    run("8-bit");

        saveAs(format, outFile);
        close();

}

   //if it is EELS
    else {

   //by saving here we obtain a shitty image, just to get the icon when
   //looking through the files 
        //saveAs(format, outFile);
        close();
        run("CSI DM3 Reader", "load=[&path]");
        //spectrum needs to be centered and calibrated
        //we get the drift of the tube, the offset energy and the dispersion
        //from the values recorded on the file
        drift = parseFloat(getTag("EELS.Acquisition.Spectrometer.Drift tube voltage"));
        offset = parseFloat(getTag("EELS.Acquisition.Spectrometer.Prism offset"));
        dispersion = parseFloat(getTag("EELS.Acquisition.Spectrometer.Dispersion"));
        energy = newArray(2048);
        //this is width of the profile, where it starts and where it ends.
        energy_width = dispersion * 2048;
        // TODO: check what is wrong with the spectra where OFFSET exist , p.e. for M4,5 lines
        //when using -3500eV, sometimes you get up to 11 eV of difference
        inicio = drift - offset - floor(energy_width / 10);
        fin = inicio + dispersion * 2048;

        run("Select All");
        // evilly copied from the macro of 
        // Version 1.0, 24-Sep-2010 Michael Schmid

        //this part gets the profile, saves it in variables x and y, and save them in
        //a 2-column txt file
        run("Plot Profile");

        Plot.getValues(x, y);

	saveAs(format, outFile);
        str = "Energy(eV)\tCounts\n"; // header 
        for (i = 0; i < x.length; i++) {
            energy[i] = inicio + dispersion * i;
            str += "" + energy[i] + "\t" + y[i] + "\n";
        }
        File.saveString(str, outFile + ".txt");
        close();
    }
print (file_dm3+" READY");
}

function getFormat() {
    //choose the output format

    formats = newArray("TIFF", "JPEG", "GIF", "PNG",
        "PGM", "BMP", "FITS", "Text Image", "ZIP", "Raw");
    Dialog.create("Output format");
    Dialog.addChoice("Convert to: ", formats, "TIFF");
    Dialog.show();
    return Dialog.getChoice();
}

function getTag(tag) {
    //get the needed tag

    info = getImageInfo();
    index1 = indexOf(info, tag);
    if (index1 == -1) return "";
    index1 = indexOf(info, "=", index1);
    if (index1 == -1) return "";
    index2 = indexOf(info, "\n", index1);
    value = substring(info, index1 + 1, index2);
    return value;
}

function crea_bar(ancho) {

    //function that prints the scalebar with certain width

    //first calculate the ideal width


    baseWidth = floor(300 * ancho);
    scaleValues = newArray(1, 2, 5);
    factor = 1;
    j = 0;
    for (t = 0; t < 20; t++) {
        scaleWidth = scaleValues[j] * factor;
        if (baseWidth > scaleWidth) {
            j++;
            if (j >= scaleValues.length) {
                j = 0;
                factor *= 10;
            }
        } else {
            t = 20;
        }
    }
    //then print it

  run("Scale Bar...", "width=&scaleWidth height=8 font=50 color=White background=Black location=[Lower Right] bold");
    return;
}

that´s it.

Regards,


#2

Thanks for sharing, @Oliver_Dieste! This is a nice, detailed example of processing all files in a directory.

Note that there are some general-purpose bare-bones examples available from the Templates menu of the Script Editor:

And a very similar example for doing batch conversion with Bio-Formats:

  • batchConvert.txt – batch convert files in a folder to TIFF using Bio-Formats

Batch convert/save as one file format to TIFF?
#3

Hi,

I write this question here because is related and noone else is talking about dm3.

In dm3 files, there is a lot of info, which can be obtainey by getimageinfo() (like i did in the dm3totiff mqcro up there).

Question: does anyone a way to 1) change that info, and/or 2) save a dm3 file.

I could not find anythink related. The point is that i am writting a macro to batch-change specimen info (in case you have been taking images for one whole day…before realizing that the specimen was not correctly set).
I guess this is going to be easier to do it on digitalmicrograph, but first i wanted to try on imagej

Best regards.


#4

In general, there are many fewer plugins which support saving to proprietary image file formats such as DM3, versus open formats like TIFF, OME-TIFF, ICS, NRRD, etc. In particular, the Bio-Formats Exporter only supports open formats.

For details on why, see this paper:

So yes, you will probably need to use Gatan’s tools to do it…


#5

Ok, thank you ! Definitely that’s what i will do.

Regards.


#6

I was having a problem converting my dm3 images to TIFF through DigitalMicrograph. My TEM diffraction patterns are dull. And, when I tried to convert them using ImageJ, the scale bar was missing.

Thank you so much Oliver for sharing this with us! This will help me so much!

Best Regards!


#7

Hi @Uchechi_Okeke , I am glad I could help someone :slight_smile:

Just in case you find it useful, I have a small update (just to write down apperture and some other details on the small image of the EELS spectra, so it is easier to read them directly) and another macro to convert the STEM files (.ser ) to tiff as well. Watch out, that this one does not work perfectly: sometimes the EDS wont be converted correctly, but at least it helps a little:

_DM3_convert.txt:

// This macro batch processes .dm3 images saved with Gatan software
// for Transmission Electron Microscope (TEM) imaging. It adds scale bar to each image
// and converts them from .dm3 to different types of image
// the diffractions obtain a scalebar with 1/nm , and the EELS are saved
// as crappy image for track, and 2-column txt file
// global author: Oliver Dieste, 21.01.2016, JRC-ITU (Karlsruhe)

// last modification: 12.09.2016 10:07

//REQUIRES CSI DM3 Reader plugin http://code.google.com/p/cornell-spectrum-imager/wiki/Home
//for the processing of EELS files. 


// partially copied from: Amirhossein Khalajhedayati, 12/10/2013, University of California Irvine, USA
// Some other parts of this code were obtained from multiple resources on the web. 

requires("1.33n");
dir = getDirectory("Choose a directory that contains dm3 files");
//i removed the output place, I prefer to have the tif where the dm3 are

format = getFormat();
bitdepth=getDepth();
start = getTime();
setBatchMode(true);
print("\\Clear")
//start the process: lets find the images in the folder and SUBFOLDERS
find(dir);


//print a count of the time
print("Processing time:   " + (getTime() - start) / 1000 + " Seconds");

//END
/////////////////////////////////////////

function find(dir) {
print("Entering "+dir);
    //showStatus("enter " + dir);
    //this function iterates in the sub-folders to find the dm3 files
    // copied from the ListFilesRecursively macro
    list = getFileList(dir);

    for (i = 0; i < list.length; i++) {
        if (endsWith(list[i], "/")) {
	//if you find a dir, go deep on it
           // print("Entering "+dir+list[i]);
	find("" + dir + list[i]);
        } 
	else if (endsWith(list[i], "dm3")) {
            //if you find a dm3, convert it!
            convert_image(list[i], dir);
           showProgress(i, list.length);
        }
    }
}

function convert_image(file_dm3, dir_dm3) {
imagestart=getTime();

    //partially borrowed from ser2tiff plugin
    //by J Kaelber at National University of Singapore on 20 July 2012
	
    //this function converts the image
    path = dir_dm3 + file_dm3;
	outputDirectory = dir_dm3;
    outFile = outputDirectory + file_dm3;
	IJ.redirectErrorMessages();

    open(path);
    getPixelSize(unit, pixelWidth, pixelHeight);

    //we check if it is EELS with the signal value
    eels = getTag("ImageTags.Meta Data.Signal");

    //if it is not EELS
    if (eels != " EELS") {
        //now we check if image or diffraction
        modo = getTag("ImageTags.Microscope Info.Operation Mode");
        if (modo != " IMAGING") {
            //for diffraction change scale unit
            run("Set Scale...", "unit=1/nm");
	}
        //for both images and diffraction create a scale bar
        //and save the images
        crea_bar(pixelWidth);
        // windows does not like tiff with 16bit. 
	   // But I let you choose 
  if(bitdepth==16){
    run("16-bit");}
else {
	
run("8-bit");}

        saveAs(format, outFile);
        close();

}

    //if it is EELS
    else {

        //by saving here we obtain a shitty image, just to get the icon when
        //looking through the files 
        //saveAs(format, outFile);
        close();
        run("CSI DM3 Reader", "load=[&path]");
        //spectrum needs to be centered and calibrated
        //we get the drift of the tube, the offset energy and the dispersion
        //from the values recorded on the file
        drift = parseFloat(getTag("ImageTags.EELS.Acquisition.Spectrometer.Drift tube voltage"));
        offset = parseFloat(getTag("ImageTags.EELS.Acquisition.Spectrometer.Prism offset"));
        dispersion = parseFloat(getTag("ImageTags.EELS.Acquisition.Spectrometer.Dispersion"));
	aperture=parseFloat(getTag("ImageTags.EELS.Acquisition.Spectrometer.Aperture label"));
	magnification=parseFloat(getTag("ImageTags.Microscope Info.Indicated Magnification"));
	exp_time=parseFloat(getTag("ImageTags.DataBar.Exposure Time"));
	sum_spectra=parseFloat(getTag("ImageTags.Acquisition.Parameters.Objects.0.Parameter 1"));
		
        energy = newArray(2048);
        //this is width of the profile, where it starts and where it ends.
        energy_width = dispersion * 2048;
        // TODO: check what is wrong with the spectra where OFFSET exist , p.e. for M4,5 lines
        //when using -3500eV, sometimes you get up to 11 eV of difference
        inicio = drift - offset - floor(energy_width / 10);
        fin = inicio + dispersion * 2048;

        run("Select All");
        // evilly copied from the macro of 
        // Version 1.0, 24-Sep-2010 Michael Schmid

        //this part gets the profile, saves it in variables x and y, and save them in
        //a 2-column txt file
        run("Plot Profile");
drawString("Aperture: "+aperture+" mm", 330, 30);
drawString("Camera length: "+magnification+" mm", 330, 40);
drawString("Exposure time: "+exp_time+" s", 330, 50);
drawString("Number of spectra: "+sum_spectra, 330, 60);
drawString("Dispersion: "+dispersion+" ev/ch", 330, 70);
drawString("Start: "+inicio+" eV", 330, 80);
drawString("End: "+fin+" eV", 330, 90);

        Plot.getValues(x, y);

	saveAs(format, outFile);
        str = "Energy(eV)\tCounts\n"; // header 
        for (i = 0; i < x.length; i++) {
            energy[i] = inicio + dispersion * i;
            str += "" + energy[i] + "\t" + y[i] + "\n";
        }
        File.saveString(str, outFile + ".txt");
        close();
    }
print (file_dm3+" READY");
}

function getFormat() {
    //choose the output format

    formats = newArray("TIFF", "JPEG", "GIF", "PNG",
        "PGM", "BMP", "FITS", "Text Image", "ZIP", "Raw");
    Dialog.create("Output format");
    Dialog.addChoice("Convert to: ", formats, "TIFF");
    Dialog.show();
    return Dialog.getChoice();
}

function getDepth(){
    //choose the output bit depth

    bits = newArray("8", "16");
    Dialog.create("Output bitdepth");
    Dialog.addChoice("Choose bit depth: ", bits, "8");
    Dialog.show();
    return Dialog.getChoice();
}

function getTag(tag) {
    //get the needed tag

    info = getImageInfo();
    index1 = indexOf(info, tag);
    if (index1 == -1) return "";
    index1 = indexOf(info, "=", index1);
    if (index1 == -1) return "";
    index2 = indexOf(info, "\n", index1);
    value = substring(info, index1 + 1, index2);
    return value;
}

function crea_bar(ancho) {

    //function that prints the scalebar with certain width

    //first calculate the ideal width


    baseWidth = floor(300 * ancho);
    scaleValues = newArray(1, 2, 5);
    factor = 1;
    j = 0;
    for (t = 0; t < 20; t++) {
        scaleWidth = scaleValues[j] * factor;
        if (baseWidth > scaleWidth) {
            j++;
            if (j >= scaleValues.length) {
                j = 0;
                factor *= 10;
            }
        } else {
            t = 20;
        }
    }
    //then print it

    run("Scale Bar...", "width=&scaleWidth height=8 font=50 color=White background=Black location=[Lower Right] bold");
    return;
}

_SER2TIFF.txt:

//This macro is adapted from the batch conversion macro in ij macro source repository
//by J Kaelber at National University of Singapore on 20 July 2012
dir = getDirectory("Choose a directory that contains SER files");
//i removed the output place, I prefer to have the tif where the dm3 are

// This macro batch processes .ser images saved with Gatan software
// for Transmission Electron Microscope (TEM) imaging. It adds scale bar to each image
// and converts them from .ser to different types of image
// the EDS obtains a crappy tif image to make it easy to find them on folders
// and a TXT file with two columns. 
// global author: Oliver Dieste, 19.10.2016, JRC-ITU (Karlsruhe)

//REQUIRES CSI DM3 Reader plugin http://code.google.com/p/cornell-spectrum-imager/wiki/Home
//for the processing of EDS files (tia spectrum reader).


format = getFormat();
start = getTime();
setBatchMode(true);
print("\\Clear")
//start the process: lets find the images in the folder and SUBFOLDERS
find(dir);


//print a count of the time
print("Processing time:   " + (getTime() - start) / 1000 + " Seconds");

//END
/////////////////////////////////////////

function find(dir) {
print("Entering "+dir);
    //showStatus("enter " + dir);
    //this function iterates in the sub-folders to find the SER files
    // copied from the ListFilesRecursively macro
    list = getFileList(dir);
    for (i = 0; i < list.length; i++) {
        if (endsWith(list[i], "/")) {
	//if you find a dir, go deep on it
           // print("Entering "+dir+list[i]);
	find("" + dir + list[i]);
        } 
	else if (endsWith(list[i], "ser")) {
            //if you find a ser, convert it!
            convert_image(list[i], dir);
           showProgress(i, list.length);
        }
    }
}

function convert_image(file_ser, dir_ser) {     
	serpath= dir_ser+file_ser;
	
	// this next line is to test the file but doesnt work       
	// IJ.redirectErrorMessages();
	
	
	if(endsWith(file_ser,"_1.ser")){
		run("TIA Reader", ".ser-reader...=&serpath");
	
		//  this part is adapted from the source poposed by @author Frederick Ding
	
		getPixelSize(unit, pw, ph);
		crea_bar(pw);
	
		// if the tiff are not in 8-bit, windows wont recognize them
		run("8-bit");
		//save it
		saveAs(format, dir_ser+file_ser+"stem");
		}
	
	//if it is not am image (ending with _1) then it´s a EDS
	else{
	
        		run("CSI TIA Reader", "load=[&serpath]");
		//IJ.redirectErrorMessages();
       	 	run("Select All");
       	 	// evilly copied from the macro of 
       	 	// Version 1.0, 24-Sep-2010 Michael Schmid
	
      	  	//this part gets the profile, saves it in variables x and y, and save them in
     	   	//a 2-column txt file
     	   	run("Plot Profile");
	
       	 	Plot.getValues(x, y);
      	  	saveAs(format, dir_ser+file_ser+"EDS");
     	   	str = "Energy(eV)\tCounts\n"; // header 
     	   	j=1;
		//this macro fails to get the correct values for some spectra
		//dont know the reason. Have go to deeper on it.
		while(j<x.length){
			str += "" + x[j] + "\t" + y[j] + "\n";
			j++;
      	  		}
	        	File.saveString(str, dir_ser+file_ser+"EDS" + ".txt");
		close();
		}

        	print (file_ser+" READY");
	}
 
  function getFormat() {
       formats = newArray("TIFF", "JPEG", "GIF", "PNG",
          "PGM", "BMP", "FITS", "Text Image", "ZIP", "Raw");
       Dialog.create("Output format");
       Dialog.addChoice("Convert to: ", formats, "TIFF");
       Dialog.show();
       return Dialog.getChoice();

}
function crea_bar(ancho) {

    //function that prints the scalebar with certain width

    //first calculate the ideal width


    baseWidth = 300 * ancho;
    scaleValues = newArray(1, 2, 3, 4, 5);
	oldWidth=1;
    factor = 1;
    j = 0;
    for (t = 0; t < 20; t++) {
        scaleWidth = scaleValues[j] * factor;
        if (baseWidth > scaleWidth) {
            j++;
	oldWidth=scaleWidth;
            if (j >= scaleValues.length) {
                j = 0;
                factor *= 10;
            }
        } else {
	scaleWidth=oldWidth;
	if(scaleWidth>ancho*512){
	scaleWidth=scaleWidth/2;}
	
            t = 20;
        }
    }
    //then print it

    run("Scale Bar...", "width=&scaleWidth height=8 font=50 color=White background=Black location=[Lower Right] bold");
    return;
}

As you can seen, the ser2tiff is not correctly commented as dm3 is, but i think it is more or less clear what it does.

In case anyone has some improvement over any of these scripts, please let me know, I am using them quite intensively now but they are not yet perfect :slight_smile:

Best regards,


#8

Hi everybody,

I know I am talking about something with a very small public, but just in case someone is interested…

I improved a little bit the macros that I created for the conversion of DM3 ( TEM, DIFF and EELS) and SER (EDS and STEM) images to a normal, readable format.

Now I blended both conversions into one Macro file, called _TEM_Convert.tx (imaginative name, isn´t it?).

If anyone would use it, and finds an error on it, please let me know.

// This macro batch processes .dm3 images saved with Gatan software
// for Transmission Electron Microscope (TEM) imaging. It adds scale bar to each image
// and converts them from .dm3 to different types of image
// the diffractions obtain a scalebar with 1/nm , and the EELS are saved
// as crappy image for track, and 2-column txt file
// global author: Oliver Dieste, 21.01.2016, JRC-ITU (Karlsruhe)

// last modification: 5.12.2017 11:17

//REQUIRES CSI DM3 Reader plugin http://code.google.com/p/cornell-spectrum-imager/wiki/Home
//for the processing of EELS files and EDS 


// partially copied from: Amirhossein Khalajhedayati, 12/10/2013, University of California Irvine, USA
// Some other parts of this code were obtained from multiple resources on the web. 

requires("1.33n");
//choose directory, format, depth and if you want to overwrite or not
dir = getDirectory("Choose a directory that contains the files");
datos=newArray("","","","","");
datos=getPreguntas();
format = datos[0];
bitdepth = datos[1];
overwrite = datos[2];
dm3=datos[3];
ser=datos[4];
start = getTime();

setBatchMode(true);


print("\\Clear")
print(overwrite);
//start the process: lets find the images in the folder and SUBFOLDERS
find(dir);
//print a count of the time
print("Processing time:   " + (getTime() - start) / 1000 + " Seconds");
//END
/////////////////////////////////////////
function find(dir) {
 print("Entering " + dir);
 //showStatus("enter " + dir);
 //this function iterates in the sub-folders to find the dm3 files
 // copied from the ListFilesRecursively macro
 list = getFileList(dir);
 for (i = 0; i < list.length; i++) {
  if (endsWith(list[i], "/")) {
   //if you find a dir, go deep on it
   find("" + dir + list[i]);
  } else if (endsWith(list[i], "dm3") && dm3) {
   //if you find a dm3, firts check if image exists.
   //if exists and we dont want to overwrite, skip it
   figure = replace(list[i], ".dm3", "." + format);
   if (File.exists(dir + figure) && !overwrite) {
       tabWindow("_dm3_", figure,"SKIPPED");
   } else {
    convert_image(list[i], dir, "dm3");
   }
  } else if (endsWith(list[i], "ser") && ser) {
   //if you find a ser,firts check if image exists.
   //if exists and we dont want to overwrite, skip it
   figure = replace(list[i], ".ser", "." + format);
   if (File.exists(dir + figure) && !overwrite) {
       tabWindow("_ser_", figure,"SKIPPED");
   } else {
    convert_image(list[i], dir, "ser");
   }
  }
  showProgress(i, list.length);
 }
}

function convert_image(file_image, dir_image, formato) {
 //this function converts the image
 imagestart = getTime();

 //partially borrowed from ser2tiff plugin
 //by J Kaelber at National University of Singapore on 20 July 2012
 path = dir_image + file_image;

 if (formato == "dm3") {
// #######################################//
 open(path);
// close();
  //run("CSI DM3 Reader", "load=[&path]");
  getPixelSize(unit, pixelWidth, pixelHeight);

  //we check if it is EELS with the signal value
  eels = getTag("ImageTags.Meta Data.Signal");

  //if it is not EELS
  if (eels != " EELS") {
// ********************************************************//
   //now we check if image or diffraction
   modo = getTag("ImageTags.Microscope Info.Imaging Mode");
   if (modo != " IMAGING") {
    //for diffraction change scale unit
    run("Set Scale...", "unit=1/"+unit);
   tipo="DIFF";
   }
else{   tipo="TEM";}
   //for both images and diffraction create a scale bar
   //and save the images
width=getWidth;
   crea_bar(pixelWidth,width);
  }

  else {
// ********************************************************//
  //if it is EELS

   //spectrum needs to be centered and calibrated
   //we get the drift of the tube, the offset energy and the dispersion
   //from the values recorded on the file
   drift = parseFloat(getTag("ImageTags.EELS.Acquisition.Spectrometer.Drift tube voltage"));
   offset = parseFloat(getTag("ImageTags.EELS.Acquisition.Spectrometer.Prism offset"));
   dispersion = parseFloat(getTag("ImageTags.EELS.Acquisition.Spectrometer.Dispersion"));
   aperture = parseFloat(getTag("ImageTags.EELS.Acquisition.Spectrometer.Aperture label"));
   magnification = parseFloat(getTag("ImageTags.Microscope Info.Indicated Magnification"));
   exp_time = parseFloat(getTag("ImageTags.DataBar.Exposure Time"));
   sum_spectra = parseFloat(getTag("ImageTags.Acquisition.Parameters.Objects.0.Parameter 1"));

   run("Select All");
   // evilly copied from the macro of 
   // Version 1.0, 24-Sep-2010 Michael Schmid

   //this part gets the profile, saves it in variables x and y, and save them in
   //a 2-column txt file
   run("Plot Profile");
   Plot.getValues(x, y);
   energy = newArray(x.length);
   //this is width of the profile, where it starts and where it ends.
   energy_width = 2 * dispersion * x.length;
   // TODO: check what is wrong with the spectra where OFFSET exist , p.e. for M4,5 lines
   //when using -3500eV, sometimes you get up to 11 eV of difference
   inicio = drift - offset - floor(energy_width / 10);
   // this is just in case the spectrum starts in negative values, for the floor to be over, not under
   if (inicio < 0) {
    inicio = inicio + 1;
   }
   fin = inicio + energy_width;

   drawString("Aperture: " + aperture + " mm", 330, 30);
   drawString("Camera length: " + magnification + " mm", 330, 40);
   drawString("Exposure time: " + exp_time + " s", 330, 50);
   drawString("Number of spectra: " + sum_spectra, 330, 60);
   drawString("Dispersion: " + dispersion + " ev/ch", 330, 70);
   drawString("Start: " + inicio + " eV", 330, 80);
   drawString("End: " + fin + " eV", 330, 90);

   str = "Energy(eV)\tCounts\n"; // header 
   for (i = 0; i < x.length; i++) {
   energy[i] = inicio + 2 * dispersion * i;
    str += "" + energy[i] + "\t" + y[i] + "\n";
   }
  File.saveString(str, path + ".txt");
  tipo="EELS";
  }
 } else if (formato == "ser") {
// #######################################//
  run("TIA Reader", ".ser-reader...=&path");
  IJ.redirectErrorMessages();
  getPixelSize(unit, pw, ph);
  width = getWidth;
  height = getHeight;
  if (width == height) {
   // then it is an image
   //  this part is adapted from the source poposed by @author Frederick Ding
   crea_bar(pw,width);
   tipo="STEM";
  } else {
   // ********************************************************//
   //if it is not am image (not square) then it´s a EDS
close();
  run("CSI TIA Reader", "load=[&path]");
   run("Select All");
saveAs("Text Image", path);
   run("Plot Profile");
    tipo="EDS";
  }
 }
   if (bitdepth == 16) {
    run("16-bit");
   } else {
    run("8-bit");
   }

   saveAs(format, path);
   tabWindow(tipo, file_image,"READY");
   close();
}

function tabWindow (tipo, image,estado) {
momento=(getTime() -start)/ 1000;
print( tipo+ "\t\t " +image+"\t\t "+estado +"\t "+momento+" s.");
}


function getPreguntas() {
 //choose the output format


 formats = newArray("tif", "jpg", "gif", "png",
  "pgm", "bmp", "fits", "txt", "zip", "raw");
 bits = newArray("8", "16");
questions=newArray("","","","","");
Dialog.create("questions");
Dialog.addChoice("Convert to: ", formats, "tif");
Dialog.addChoice("Choose bit depth: ", bits, "8");
Dialog.addCheckbox("Overwrite images? ", false);
Dialog.addCheckbox("Convert TEM/DIFF/EELS? ", true);
Dialog.addCheckbox("Convert STEM/EDS? ", true);
 Dialog.show();
questions[0]=Dialog.getChoice();
questions[1]=Dialog.getChoice();
questions[2]=Dialog.getCheckbox();
questions[3]=Dialog.getCheckbox();
questions[4]=Dialog.getCheckbox();
 return questions;
}

function getTag(tag) {
 //get the needed tag

 info = getImageInfo();
 index1 = indexOf(info, tag);
 if (index1 == -1) return "";
 index1 = indexOf(info, "=", index1);
 if (index1 == -1) return "";
 index2 = indexOf(info, "\n", index1);
 value = substring(info, index1 + 1, index2);
 return value;
}

function crea_bar(ancho, pixel) {

 //function that prints the scalebar with certain width

 //first calculate the ideal width
// it is a third of the size of one pixel times the number of pixels
 baseWidth = ancho* pixel/3;
 scaleValues = newArray(1, 2, 3, 4, 5);
 oldWidth = 1;
 factor = 1;
 j = 0;
 for (t = 0; t < 20; t++) {
  scaleWidth = scaleValues[j] * factor;
  if (baseWidth > scaleWidth) {
   j++;
   oldWidth = scaleWidth;
   if (j >= scaleValues.length) {
    j = 0;
    factor *= 10;
   }
  } else {
   scaleWidth = oldWidth;
   if (scaleWidth > baseWidth) {
    scaleWidth = scaleWidth / 2;
   }

   t = 20;
  }
 }
 //then print it

 run("Scale Bar...", "width=&scaleWidth height=8 font=50 color=White background=Black location=[Lower Right] bold");
 return;
}

Jython ShortProcessor un/signed issue
#10

Hi again,
I keep on posting in this threat to avoid spamming the rest of users here :slight_smile:

I have updated the macro. Still, a lot to do, but it helps more and more (at least to me).
No it also gets the information saved on the .emi files (HT, user name, XYZ-a-b position…).
I made a first try to extract the quantification information, but I have a problem with that: the data seems to be “just there”, with no clear indication to which spectrum relates each quantification (if there are several spectra on the same .emi file). I have to work further.

Here it is. As usual, I would love to have any comment.

// This macro batch processes .dm3 images saved with Gatan software
// for Transmission Electron Microscope (TEM) imaging. It adds scale bar to each image
// and converts them from .dm3 to different types of image
// the diffractions obtain a scalebar with 1/nm , and the EELS are saved
// as crappy image for track, and 2-column txt file
// it also converts .ser files saved with TIA (FEI) to images, adds scalebar to them
// and for the EDS a crappy image is created and a text file with the data
// global author: Oliver Dieste, 21.01.2016, JRC-ITU (Karlsruhe)

// last modification: 29.06.2018 13:17

//REQUIRES CSI DM3 Reader plugin http://code.google.com/p/cornell-spectrum-imager/wiki/Home
//for the processing of EELS files and EDS 

// partially copied from: Amirhossein Khalajhedayati, 12/10/2013, University of California Irvine, USA
// Some other parts of this code were obtained from multiple resources on the web. 

//in principle we do not want to deal with old versions of imagej. Just get a new version :)
requires("1.33n");

//choose directory
dir = getDirectory("Choose a directory that contains the files");
// now create a question form to ask
// overwrite images? convert DM3? convert SER ?
datos = newArray("","", "", "", "", "");
datos = getPreguntas();
format = datos[0];
bitdepth = datos[1];
overwrite = datos[2];
dm3 = datos[3];
ser = datos[4];
emi=datos[5];
start = getTime();
setBatchMode(true);

//clean  the log 
print("\\Clear")
print(overwrite);
//start the process: lets find the images in the folder and SUBFOLDERS
find(dir);
//print a count of the time
print("Processing time:   " + (getTime() - start) / 1000 + " Seconds");
//END
//#####################################################//
function find(dir) {
  // this is the function that searches for files inside folder and subfolders
  print("Entering " + dir);

  //showStatus("enter " + dir);
  //this function iterates in the sub-folders to find the dm3 files
  // copied from the ListFilesRecursively macro
  list = getFileList(dir);
  for (i = 0; i < list.length; i++) {
    if (endsWith(list[i], "/")) {
      //if you find a dir, go deep on it
      find("" + dir + list[i]);
    } else if (endsWith(list[i], "dm3") && dm3) {
      //if you find a dm3, firts check if image exists.
      //if exists and we dont want to overwrite, skip it
      figure = replace(list[i], ".dm3", "." + format);
      if (File.exists(dir + figure) && !overwrite) {
        tabWindow("  dm3  " + figure + "  SKIPPED");
      } else {
        tabWindow("dm3  " + list[i]);
        convert_dm3(list[i], dir);
      }
    } else if (endsWith(list[i], "ser") && ser) {
      //if you find a ser,firts check if image exists.
      //if exists and we dont want to overwrite, skip it
      figure = replace(list[i], ".ser", "." + format);
      if (File.exists(dir + figure) && !overwrite) {

        tabWindow("  ser  " + figure + "  SKIPPED");
      } else {
        tabWindow("ser  " + list[i]);
        convert_ser(list[i], dir);

      }
    } else if (endsWith(list[i], "emi") && emi) {
      //if you find a emi,lets try to get the data on it and save it as xml
      tabWindow("emi " + list[i]);
      convert_emi(list[i], dir);
    }
    showProgress(i, list.length);
  }
}

//#####################################################//
function convert_emi(file_name, path_name) {
  imagestart = getTime();
  //if we find a emi file, just save the data on iit as xml file
  complete_text = File.openAsString(path_name + file_name);

  // we call for the data of the file about the microscope
  Texto = replace(replace(getSubstring(complete_text, "<ObjectInfo>", "</ObjectInfo>"), "&gt;", ">"), "&lt;", "<");
  calString = "<ObjectInfo>" + Texto + "</ObjectInfo>";
  //and save it as xml file
  File.saveString(calString, path_name + replace(file_name,".emi","_info_") + ".xml");

//now we call for the quantification
trimm=replace(file_name,".emi","");
starting="";
ending="Normalp";
  Texto = getSubstring(complete_text, starting, ending);
  calString = "" + Texto + "";
  //and save it as txt file
if(Texto!=""){
  File.saveString(calString, path_name + replace(file_name,".emi","_quant_") + ".txt");
}
}
//#####################################################//
function convert_dm3(file_name, path_name) {

  //this function converts the image
  imagestart = getTime();

  //partially borrowed from ser2tiff plugin
  //by J Kaelber at National University of Singapore on 20 July 2012
  path = path_name + file_name;

  open(path);
  
  // close();
  //run("CSI DM3 Reader", "load=[&path]");
  getPixelSize(unit, pixelWidth, pixelHeight);

  //we check if it is EELS with the signal value
  eels = getTag("ImageTags.Meta Data.Signal");
  
  //if it is not EELS
  if (eels != " EELS") {
    // ********************************************************//
    //now we check if image or diffraction
    modo = getTag("ImageTags.Microscope Info.Imaging Mode");
    if (modo != " IMAGING") {
      //for diffraction change scale unit
      run("Set Scale...", "unit=1/" + unit);
    } 

    //for both images and diffraction create a scale bar
    //and save the images
    width = getWidth;

   crea_bar(pixelWidth, width);
  } else {
    // ********************************************************//
    //if it is EELS
    //spectrum needs to be centered and calibrated
    //we get the drift of the tube, the offset energy and the dispersion
    //from the values recorded on the file
    drift = parseFloat(getTag("ImageTags.EELS.Acquisition.Spectrometer.Drift tube voltage"));
    offset = parseFloat(getTag("ImageTags.EELS.Acquisition.Spectrometer.Prism offset"));
    dispersion = parseFloat(getTag("ImageTags.EELS.Acquisition.Spectrometer.Dispersion"));
    aperture = parseFloat(getTag("ImageTags.EELS.Acquisition.Spectrometer.Aperture label"));
    magnification = parseFloat(getTag("ImageTags.Microscope Info.Indicated Magnification"));
    exp_time = parseFloat(getTag("ImageTags.DataBar.Exposure Time"));
    sum_spectra = parseFloat(getTag("ImageTags.Acquisition.Parameters.Objects.0.Parameter 1"));

    run("Select All");
    // evilly copied from the macro of 
    // Version 1.0, 24-Sep-2010 Michael Schmid

    //this part gets the profile, saves it in variables x and y, and save them in
    //a 2-column txt file
    run("Plot Profile");
    Plot.getValues(x, y);
    energy = newArray(x.length);
    //this is width of the profile, where it starts and where it ends.
    energy_width = 2 * dispersion * x.length;
    // TODO: check what is wrong with the spectra where OFFSET exist , p.e. for M4,5 lines
    //when using -3500eV, sometimes you get up to 11 eV of difference
    inicio = drift - offset - floor(energy_width / 10);
    // this is just in case the spectrum starts in negative values, for the floor to be over, not under
    if (inicio < 0) {
      inicio = inicio + 1;
    }
    fin = inicio + energy_width;

    drawString("Aperture: " + aperture + " mm", 330, 30);
    drawString("Camera length: " + magnification + " mm", 330, 40);
    drawString("Exposure time: " + exp_time + " s", 330, 50);
    drawString("Number of spectra: " + sum_spectra, 330, 60);
    drawString("Dispersion: " + dispersion + " ev/ch", 330, 70);
    drawString("Start: " + inicio + " eV", 330, 80);
    drawString("End: " + fin + " eV", 330, 90);

    str = "Energy(eV)\tCounts\n"; // header 
    for (i = 0; i < x.length; i++) {
      energy[i] = inicio + 2 * dispersion * i;
      str += "" + energy[i] + "\t" + y[i] + "\n";
    }
    File.saveString(str, replace(path,".dm3","")+ ".txt");
  }
  if (nImages != 0) {
    if (bitdepth == 16) {
      run("16-bit");
    } else {
      run("8-bit");
    }
    saveAs(format, path);
    tabWindow("READY");
    close();
  }
    
}
//#####################################################//
function convert_ser(file_name, path_name) {
    //this function converts the image
    imagestart = getTime();
path=path_name+file_name;
    //partially borrowed from ser2tiff plugin
    //by J Kaelber at National University of Singapore on 20 July 2012
    
   
    run("TIA Reader", ".ser-reader...=&path");
   // run("CSI TIA Reader", "load=[&path]");


    width = getWidth;
    height = getHeight;
    //if(endsWith(path,"_1.ser")){

    if (width == height) {
      getPixelSize(unit, pw, ph);
      // then it is an image
      doble = pw;
      //run("Set Scale...", "distance=1 known=&doble pixel=1 unit=&unit");
      crea_bar(doble, width);

      // then it is an image
      //  this part is adapted from the source poposed by @author Frederick Ding
    } else {

      // ********************************************************//
      //if it is not am image (not square) then it´s a EDS

      close();
      run("CSI TIA Reader", "load=[&path]");
      //run("TIA Reader", ".ser-reader...=&path");
      //run("CSI TIA Reader", "load=[&path]");
      //IJ.redirectErrorMessages();
      if (nImages != 0) {
        run("Select All");
        saveAs("Text Image", path);
        run("Plot Profile");
      }

    }
  if (nImages != 0) {
    if (bitdepth == 16) {
      run("16-bit");
    } else {
      run("8-bit");
}
    saveAs(format, path);
    tabWindow("READY");
    close();
  }
}
//#####################################################//
function getSubstring(string, prefix, postfix) {
    start = indexOf(string, prefix) + lengthOf(prefix);
    end = start + indexOf(substring(string, start), postfix);
    if (start >= 0 && end >= 0)
      return substring(string, start, end);
    else
      return "";
  }
//#####################################################//
function tabWindow(estado) {
    momento = (getTime() - start) / 1000;
    print(estado + "\t " + momento + " s.");
  }
//#####################################################//
function getPreguntas() {
    //choose the output format

    formats = newArray("tif", "jpg", "gif", "png",
      "pgm", "bmp", "fits", "txt", "zip", "raw");
    bits = newArray("8", "16");
    questions = newArray("", "", "", "", "","");
    Dialog.create("questions");
    Dialog.addChoice("Convert to: ", formats, "tif");
    Dialog.addChoice("Choose bit depth: ", bits, "8");
    Dialog.addCheckbox("Overwrite images? ", false);
    Dialog.addCheckbox("Convert TEM/DIFF/EELS? ", true);
    Dialog.addCheckbox("Convert STEM/EDS? ", true);
Dialog.addCheckbox("Retrieve data from EMI? ", true);
    Dialog.show();
    questions[0] = Dialog.getChoice();
    questions[1] = Dialog.getChoice();
    questions[2] = Dialog.getCheckbox();
    questions[3] = Dialog.getCheckbox();
    questions[4] = Dialog.getCheckbox();
    questions[5] = Dialog.getCheckbox();
    return questions;
  }
//#####################################################//
function getTag(tag) {
    //get the needed tag

    info = getImageInfo();
    index1 = indexOf(info, tag);
    if (index1 == -1) return "";
    index1 = indexOf(info, "=", index1);
    if (index1 == -1) return "";
    index2 = indexOf(info, "\n", index1);
    value = substring(info, index1 + 1, index2);
    return value;
  }
//#####################################################//
function crea_bar(ancho, pixel) {

 //function that prints the scalebar with certain width

 //first calculate the ideal width
// it is a third of the size of one pixel times the number of pixels
 baseWidth = ancho* pixel/3;
 scaleValues = newArray(1, 2, 3, 4, 5);
 oldWidth = 1;
 factor = 1;
 j = 0;
 for (t = 0; t < 20; t++) {
  scaleWidth = scaleValues[j] * factor;
  if (baseWidth > scaleWidth) {
   j++;
   oldWidth = scaleWidth;
   if (j >= scaleValues.length) {
    j = 0;
    factor *= 10;
   }
  } else {
   scaleWidth = oldWidth;
   if (scaleWidth > baseWidth) {
    scaleWidth = scaleWidth / 2;
   }

   t = 20;
  }
 }
 //then print it

 run("Scale Bar...", "width=&scaleWidth height=8 font=50 color=White background=Black location=[Lower Right] bold");
 return;
}

#11

Hello everybody,

AS usual, I just come to update the MACRO i created for the people using FEI Tecnai microscopes, with the Digitalmicrograph for TEM and TIA for STEM.

I am quite proud of what i managed to get on the last few months, and I think I will not be updating the macro anymore.

I made a resume of what it does:
DM3
IMAGE -> converts to tif (or other format as jpg) and adds adequate SCALEBAR.
ELE.DIFF-> converts to tif and ans adequate SCALEBAR (1/nm p.e.).
EELS -> creates 2-columns .txt file, and tif image with the profile
SER
IMAGE -> converts to tif and adds SCALEBAR
EDS -> creates 2-columns .txt file, and a tif image with the profile
LINE SCAN -> creates n-columns .txt file, and a tif image with the spectra as pages
MAPPING -> creates a tiff with a page for each energy (I removed the 3-energies stuff because it was painful).
EMI
Gets quantifications related to each SER file embedded on the EMI File. Writes them in .txt files
Gets all the metadata and writes it as xml files, each for each SER file embeded on the EMI File.
If an Image was obtained in HAADF (and saved from the SER1 file) then it creates an image for each SER file and writes on it WHERE the EDS was performed.

TODO: I did not figure it out how to extract the images and spectra directly from the EMI files (even though i know they are there) to solve the “failed spectra” problem when the spectrum was stopped before finishing.
The line scan does not create an Image with the line for the scanning, because the TIA does not create a SER file for the Image, so I cannot get it from the EMI.
More testing and so on. If anyone wants to, I can help :slight_smile:

/// This macro batch processes .dm3 images saved with Gatan software
// for Transmission Electron Microscope (TEM) imaging. It adds scale bar to each image
// and converts them from .dm3 to different types of image
// the diffractions obtain a scalebar with 1/nm , and the EELS are saved
// as crappy image for track, and 2-column txt file
// it also converts .ser files saved with TIA (FEI) to images, adds scalebar to them
// and for the EDS a crappy image is created and a text file with the data
//finally, it gets the data from EMI files, and produces an XML file with the metadata
//and, in case, uses the Image created by SER converter to write WHERE the EDS have been performed
// global author: Oliver Dieste, 21.01.2016, JRC-ITU (Karlsruhe)

// last modification: 30.01.2019 10:00
// I would love to call this version the 1.0, as it is already perfectly functional, and
//does not seem to crash (too often). 


//REQUIRES CSI DM3 Reader plugin http://code.google.com/p/cornell-spectrum-imager/wiki/Home
//for the processing of EELS files and EDS
// it also REQUIRES TIA Reader. I know, it is weird to need CSI READER and TIA READER
// but this is because images are better managed by TIA READER, while 
//spectra must be managed by CSI TIA READER
// partially copied from: Amirhossein Khalajhedayati, 12/10/2013, University of California Irvine, USA
// Some other parts of this code were obtained from multiple resources on the web.

//in principle we do not want to deal with old versions of imagej. Just get a new version :)

requires("1.45s");

//choose directory
dir = getDirectory("Choose a directory that contains the files");
// now create a question form to ask
// overwrite images? convert DM3? convert SER ? EMI?
datos = newArray("", "", "", "", "", "");
//this is a function (see at the end of the file)
datos = getPreguntas();
format = datos[0];
bitdepth = datos[1];
overwrite = datos[2];
dm3 = datos[3];
ser = datos[4];
emi = datos[5];
start = getTime();
setBatchMode(true);
totaldm3 = 0;
totalser = 0;
totalemi = 0;
listdm3 = newArray(0);
listser = newArray(0);
listEMI = newArray(0);

setOption("ExpandableArrays", true);
totalfailed = 0;
totalskipped = 0;
espazo = "   ";
var quantification = "";
//clean  the log
print("\\Clear");
//start the process: lets find the images in the folder and SUBFOLDERS
find(dir);
//print a count of the time
print("######END######");
print("Processing time:   " + (getTime() - start) / 1000 + " Seconds");
print("SER files converted: " + totalser);
print("EMI  files converted: " + totalemi);
print("DM3 files converted: " + totaldm3);
print("        files failed:         " + totalfailed);
print("        files skipped:     " + totalskipped);
//END
//#####################################################//
function find(dir) {
  // this is the function that searches for files inside folder and subfolders
  //showStatus("enter " + dir);
  //this function iterates in the sub-folders to find the dm3 files
  // copied from the ListFilesRecursively macro
  list = getFileList(dir);
  for (i = 0; i < list.length; i++) {
    if (endsWith(list[i], "/")) {
      
      //if you find a dir, go deep on it
      find("" + dir + list[i]);
    } else if (endsWith(list[i], "dm3") && dm3) {
      listdm3 = Array.concat(listdm3, dir + list[i]);
      //if it is a dm3, add it to the list
    } else if (endsWith(list[i], "ser") && ser) {
      listser = Array.concat(listser, dir + list[i]);
      //if it is a ser, add it to the list
    } else if (endsWith(list[i], "emi") && emi) {
      listEMI = Array.concat(listEMI, dir + list[i]);
      //if it is a emi, add it to the list
    }
  }

  //now we go through the lists to convert the files in order
  for (i = 1; i < listdm3.length; i++) {
    //first for DM3
    figure = replace(listdm3[i], ".dm3", "." + format);
    //we check if the image is already there. If we dont want to overwrite, we skip it.
    if ((File.exists(figure) && overwrite=="No")||(!File.exists(figure) && overwrite=="Only update")) {
      print(espazo + "SKIPPED DM3 " + figure);
      totalskipped++;
    } else{
      convert_dm3(listdm3[i]);
    }
    showProgress(i, listdm3.length + listser.length + listEMI.length);
    //this part is to be able to stop the macro at any time pressing BAR
    interruptMacro = isKeyDown("space");
    if (interruptMacro == true) {
      print("interrupted");
      setKeyDown("none");
      break;
    }
  }
  for (i = 1; i < listser.length; i++) {
    //now for SER
    //we check if the image is already there. If we dont want to overwrite, we skip it.
    figure = replace(listser[i], ".ser", "." + format);
    if ((File.exists(figure) && overwrite=="No")||(!File.exists(figure) && overwrite=="Only update")) {
      print(espazo + "SKIPPED SER" + figure);
      totalskipped++;
    } else {
      convert_ser(listser[i]);
    }
    //we try to make the progress bar as big as the number of total images, and move on it
    showProgress(
      i + listdm3.length,
      listdm3.length + listser.length + listEMI.length
    );

  }
  for (i = 1; i < listEMI.length; i++) {
    //now for SER
    //we check if the image is already there. If we dont want to overwrite, we skip it.
    figure = replace(listEMI[i], ".emi", "." + format);
    if ((File.exists(figure) && overwrite=="No")||(!File.exists(figure) && overwrite=="Only update")) {
      print(espazo + "SKIPPED EMI" + figure);
      totalskipped++;
    } else {
      convert_emi(listEMI[i]);
    }
    showProgress(
      listdm3.length + listser.length + i,
      listdm3.length + listser.length + listEMI.length
    );

  }
}
//#####################################################//
function convert_emi(file_name) {
  imagestart = getTime();
  //if we find a emi file, we open it as text
  resto = File.openAsString(file_name);
  if (resto != "") {
    //now we go for the quantification
    nome = split(file_name, "\\/");
    trimm = replace(nome[nome.length - 1], ".emi", "");
    restoxml = resto;
    //trimm the raw data from starting to Normalp , that it is where the image starts
    resto = getSubstring(resto, "0", "Normalp");

    //we will save a text file for each quantification found
    //with the name of this file. This is done because all the LOG file in the TIA
    //software is saved on each emi file, unless you clear it out every time
    starting = "= = = Document: " + trimm;
    ending = "= = = E D X   Q u a n t i f i c a t i o n   R e s u l t s = = =";

    i = 0;
    do {
    	//this bucle searches for "start", then for "end", and saves the text between them as quantification
      desde = indexOf(resto, starting);
      if (desde > 0) {
        ata = indexOf(resto, ending, desde);
        if (ata < desde) {
          quantification = substring(resto, desde);
          resto = "";
        } else {
          quantification = substring(resto, desde, ata);
          resto = substring(resto, ata);
        }
        if (lengthOf(quantification) > 500) {
          //here we save it
          File.saveString(
            quantification,
            replace(file_name, ".emi", "Q-" + i + ".txt")
          );
        }
        i++;
      } else {
        resto = "";
      }
    } while (resto != "");
    //when the resto is empty, there is nothing else to read
    

    //repeat for xml. We will get the XML file with the METADATA
    //again, it appears for each SER saved, so we will have several usually
    i = 0;
    j = 0;
    starting = "<ObjectInfo>";
    ending = "</ObjectInfo>";
    do {
      desde = indexOf(restoxml, starting);
      if (desde > 0) {
        ata = indexOf(restoxml, ending, desde);
        if (ata < desde) {
          quantification = "";
          restoxml = "";
        } else {
          quantification = replace(
            replace(getSubstring(restoxml, starting, ending), "&gt;", ">"),
            "&lt;",
            "<"
          );
          restoxml = substring(restoxml, ata);
        }
        if (lengthOf(quantification) > 500) {
          j++;
          File.saveString(
            starting + quantification + ending,
            replace(file_name, ".emi", "_" + j + ".xml")
          );
        }

        //inside the metadata we may find position or area where EDS was done. Check it

        position = getSubstring(
          quantification,
          "<ScanArea>(",
          ") um</ScanArea>"
        );
        beam = getSubstring(
          quantification,
          "<BeamPosition>(",
          ") um</BeamPosition>"
        );
        //we will just get the first image of the series to write on it
        figure = replace(file_name, ".emi", "_1.tif");

        if (File.exists(figure) && (position > "" || beam > "")) {
          open(figure);
          //if we have an image to write in, we will put a square and "EDS X" on it
          //there may be a "position" or "area". We want to draw a square there
          if (position > "") {
            sep = "\\) \\- \\(";
            position = replace(position, sep, "\\$");
            position = replace(position, ",", "\\$");
            preposition = split(position, "\\$");

            startx = parseFloat(preposition[0]);
            starty = parseFloat(preposition[1]);
            endx = parseFloat(preposition[2]);
            endy = parseFloat(preposition[3]);
          } else {
            beam = replace(beam, ",", "\\$");
            preposition = split(beam, "\\$");

            startx = parseFloat(preposition[0]);
            starty = parseFloat(preposition[1]);
            endx = startx;
            endy = starty;
          }
          width = getWidth;
          getPixelSize(unit, pixelWidth, pixelHeight);
          if (unit == "nm") {
            pixelWidth = pixelWidth / 1000;
          }
//ok, now we convert the positions into pixels, because until now they are in nm/um
          startx = floor(startx / pixelWidth) + width / 2;
          starty = width / 2 - floor(starty / pixelWidth) ;
          endx = floor(endx / pixelWidth) + width / 2;
          endy = width / 2 - floor(endy / pixelWidth);
//in case they are the same, we extend the end a little
          if (endx - startx <= 0) {
            temporal = endx;
            endx = startx + 1;
            startx = temporal;
          }
          if (endy - starty <= 0) {
            temporal = endy;
            endy = starty + 1;
            starty = temporal;
          }
          //we want the EDS square to be colorful
          run("RGB Color");
          setForegroundColor(255, 0, 0);
          //caferefully we choose a font size adapted to the image size. Also the linewidth
          letra = (60 * width) / 2048;
          linha = (10 * width) / 2048;
          setFont("SansSerif", letra, " antialiased");
          makeRectangle(startx, starty, endx - startx, endy - starty);
          run("Properties... ", "name=eds stroke=red width=linha fill=none");
          run("Draw");
          //did not test this part: if we will write out of the image, just go back
          if (endx + 4 * letra > width) {
            endx = endx - 4 * letra;
          }
          if (endy + 4 * letra > width) {
            endy = endy - 4 * letra;
          }
          //write the text and save it
          makeText("EDS " + j, endx, endy);
          run("Draw");
          figure = replace(file_name, ".emi", "_" + j + "-EDS.tif");
          save(figure);
          close();
        }

        i++;
      } else {
        restoxml = "";
      }
    } while (restoxml != "" && i < 20);
	//ready. Lets close this function and go for the next picture :)
    print(espazo + "READY EMI " + file_name);
    totalemi++;
  } else {
    print(espazo + "FAILED EMI" + file_name);
    totalfailed++;
  }
}
//#####################################################//
function convert_ser(file_name) {
  //this function converts the image
  path = file_name;
  
  if (nImages > 0) {
    close("*");
  }
  //partially borrowed from ser2tiff plugin
  //by J Kaelber at National University of Singapore on 20 July 2012
  IJ.redirectErrorMessages();

  run("CSI TIA Reader", "load=[&path]");
//first check if the reader could open an image
  if (nImages > 0) {
    colheinfo = getImageInfo();
//checking carefully the info obtained from that command, we found out that some keywords appear
//only on certain type of files. Wew make use of it
    if (indexOf(colheinfo, "Depth:") > 0) {
      //if it is a map, we pretend to do something great, choosing energy to get maps
      //but this is not yet great. Just ask the energies and save the mapping for each
	//on a 2.0 version we could think on have a database of energies and just choose elements, but it was too long
//	      energia = newArray("", "", "");
//	      Dialog.create("Mapping");
//	      Dialog.addMessage(
//	        "there seems to be a Mapping. Choose energy windows for analyses"
//	      );
//	
//	      Dialog.addNumber("energy1", 0.01, 2, 4, "keV");
//	      Dialog.addNumber("energy2", 0.01, 2, 4, "keV");
//	      Dialog.addNumber("energy3", 0.01, 2, 4, "keV");
//	      Dialog.show();
//	      energia[0] = 100*Dialog.getNumber(); energia[1] = 100*Dialog.getNumber(); energia[2] = 100*Dialog.getNumber();
//	//for(i=0;i<=3;i++{energia[i]=energia[i]*100;}
//		if(energia[0]<nSlices&&energia[1]<nSlices&&energia[2]<nSlices&&(energia[0]>0 ||energia[1]>0||energia[2]>0)){
//			energies="  slices="+energia[0]+","+energia[1]+","+energia[2];
//		//extract the images corresponding to those energies.
//		run("Make Substack...", energies);
      
      run(bitdepth+"-bit");
      
        //this set scale are on the plots along the convert macro to allow Windows to understand the size of the tif figures.
	run("Set Scale...", "distance=0 known=0 pixel=1 unit=pixel");
    }
    
   
    else if (indexOf(colheinfo, "Height:  1 pixels") > 0) {
      // then it´s a EDS
	
      run("Select All");
    //  saveAs("Text Image", path);
       x = getProfile();
       energy = newArray(x.length);
       str = "Energy(eV)\tCounts\n"; // header
       for (i = 0; i < x.length; i++) {
        energy[i] = i/100;
        str += "" + energy[i] + "\t" + x[i] + "\n";
      }
      File.saveString(str, replace(path, ".ser", "") + ".txt");

      
    //just make it slightly nicer, with normal axis labels and so on
    setFont("Serif", 12, "antialiased");
    setColor("black");
    setJustification("left");
	Plot.create("EELS", "Energy(eV)", "Counts");
	Plot.setLineWidth(2);
	Plot.setColor("red");
	Plot.add("line",energy,x);
    Plot.setLimits(0, 20, 0, NaN);
	Plot.setColor("black");
    //Plot.addText(s,0.65,0.1);
    Plot.update();
    run("Set Scale...", "distance=0 known=0 pixel=1 unit=pixel");

    } else if (indexOf(colheinfo, "Resolution") > 0) {
      // it is a line profile
		//we save it as eds, and thats all. What else could we do here?
		//we just save it as stack (one tif image with several pages) and text file
		//first we save it as text
	run("Select All");
    saveAs("Text Image", path);
    //then we close it
 //	close();
    //run("TIA Reader", ".ser-reader...=&path");
	//run("Images to Stack", "name=[Line Profile] title=[] use");
height = getHeight;
width=getWidth;
id=getImageID();
for (i=0;i<height;i++){
	makeRectangle(0,i,width,1);
	x=getProfile();
	Plot.create("EDS PROFILE-"+i, "Energy(keV)", "Counts");
	Plot.setLineWidth(2);
	Plot.setColor("red");
	Plot.setLimits(0, 2000, 0, NaN);
	Plot.add("line",x);
    Plot.update();
	selectImage(id);
	}
	close("*.ser");
	run("Images to Stack", "name=Stack title=[] use");
	

	//run("Set Scale...", "distance=0 known=0 pixel=1 unit=pixel");
	}
    else {
      // then it is an image
      close();
      run("TIA Reader", ".ser-reader...=&path");
        //  this part is adapted from the source poposed by @author Frederick Ding
        getPixelSize(unit, pw, ph);
        // then it is an image
        doble = pw;
        width = getWidth;
        height = getHeight;
        //run("Set Scale...", "distance=1 known=&doble pixel=1 unit=&unit");
        crea_bar(doble, width);     
        run(bitdepth+"-bit"); 
    }
//just in case we want the image to be in 16bit. If not, set it to 8bit
        
        saveAs(format, path);
        
    print(espazo + "READY SER " + file_name);
    totalser++;
    close("*");
  }
  else {
  	//if there was no opened image, it means it failed.
	print(espazo + "FAILED SER " + file_name);
    totalfailed++;
  }
}
//#####################################################//
function convert_dm3(file_name) {
  //this function converts the image
  imagestart = getTime();

  //partially borrowed from ser2tiff plugin
  //by J Kaelber at National University of Singapore on 20 July 2012
  path = file_name;

  open(path);
  if (nImages > 0) {
    // close();
    //run("CSI DM3 Reader", "load=[&path]");
    getPixelSize(unit, pixelWidth, pixelHeight);

    //we check if it is EELS with the signal value
    eels = getTag("ImageTags.Meta Data.Signal");

    //if it is not EELS
    if (eels != " EELS") {
      // ********************************************************//
      //now we check if image or diffraction
      modo = getTag("ImageTags.Microscope Info.Imaging Mode");
      if (modo != " IMAGING") {
        //for diffraction change scale unit
        run("Set Scale...", "unit=1/" + unit);
      }

      //for both images and diffraction create a scale bar
      //and save the images
      width = getWidth;

      crea_bar(pixelWidth, width);
      run(bitdepth+"-bit");
    } else {
     close();
    run("CSI DM3 Reader", "load=[&path]");
      // ********************************************************//
      //if it is EELS
      //spectrum needs to be centered and calibrated
      //we get the drift of the tube, the offset energy and the dispersion
      //from the values recorded on the file
      drift = parseFloat(
        getTag("ImageTags.EELS.Acquisition.Spectrometer.Drift tube voltage")
      );
      offset = parseFloat(
        getTag("ImageTags.EELS.Acquisition.Spectrometer.Prism offset")
      );
      dispersion = parseFloat(
        getTag("ImageTags.EELS.Acquisition.Spectrometer.Dispersion")
      );
      aperture = parseFloat(
        getTag("ImageTags.EELS.Acquisition.Spectrometer.Aperture label")
      );
      magnification = parseFloat(
        getTag("ImageTags.Microscope Info.Indicated Magnification")
      );
      exp_time = parseFloat(getTag("ImageTags.DataBar.Exposure Time"));
      sum_spectra = parseFloat(
        getTag("ImageTags.Acquisition.Parameters.Objects.0.Parameter 1")
      );

      // evilly copied from the macro of
      // Version 1.0, 24-Sep-2010 Michael Schmid

      //this part gets the profile, saves it in variables x and y, and save them in
      //a 2-column txt file

      run("Select All");
      x = getProfile();
      //run("Plot Profile");
      //Plot.getValues(x, y);
      energy = newArray(x.length);
      //this is width of the profile, where it starts and where it ends.
      energy_width = 2 * dispersion * x.length;
      // TODO: check what is wrong with the spectra where OFFSET exist , p.e. for M4,5 lines
      //when using -3500eV, sometimes you get up to 11 eV of difference

      inicio = drift - offset - floor(energy_width / 10);
      // this is just in case the spectrum starts in negative values, for the floor to be over, not under

      if (inicio < 0) {
        inicio = inicio + 1;
      }
      fin = inicio + energy_width;

      str = "Energy(eV)\tCounts\n"; // header
      for (i = 0; i < x.length; i++) {
        energy[i] = inicio + 2 * dispersion * i;
        str += "" + energy[i] + "\t" + x[i] + "\n";
      }
      File.saveString(str, replace(path, ".dm3", "") + ".txt");
    
      s =
        "Aperture: " +
        aperture +
        " mm" +
        "\n" +
        "Camera length: " +
        magnification +
        " mm" +
        "\n" +
        "Exposure time: " +
        exp_time +
        " s" +
        "\n" +
        "Number of spectra: " +
        sum_spectra +
        "\n" +
        "Dispersion: " +
        dispersion +
        " ev/ch";
    setFont("Serif", 12, "antialiased");
    setColor("black");
    setJustification("left");
	Plot.create("EELS", "Energy(eV)", "Counts");
	Plot.setLineWidth(2);
	Plot.setColor("red");
	Plot.add("line",energy,x);
	Plot.setColor("black");
    Plot.addText(s,0.65,0.1);
    Plot.update();
    run("Set Scale...", "distance=0 known=0 pixel=1 unit=pixel");
    }
      
	
      saveAs(format, path);
      
      print(espazo + "READY DM3 " + file_name);
      totaldm3++;
      close();
    
  } else {
    print(espazo + "FAILED DM3 " + file_name);
    totalfailed++;
  }
}
//#####################################################//
function getSubstring(string, prefix, postfix) {
  //this function has been stolen somewhere on the net, not sure where
  //it gets a substring out of a string
  start = indexOf(string, prefix) + lengthOf(prefix);
  end = start + indexOf(substring(string, start), postfix);
  if (start >= 0 && end > start) return substring(string, start, end);
  else return "";
}
//#####################################################//
function getPreguntas() {
  //choose the output format

  formats = newArray(
    "tif",
    "jpg",
    "gif",
    "png",
    "pgm",
    "bmp",
    "fits",
    "txt",
    "zip",
    "raw"
  );
  bits = newArray("8", "16","24");
  items = newArray("Yes", "No", "Only update");
  questions = newArray("", "", "", "", "", "");
  Dialog.create("questions");
  Dialog.addChoice("Convert to: ", formats, "tif");
  Dialog.addChoice("Bit depth: ", bits, "8");
  Dialog.addRadioButtonGroup("Overwrite", items, 1, 3, "No");
  Dialog.addCheckbox("Convert TEM/DIFF/EELS? ", true);
  Dialog.addCheckbox("Convert STEM/EDS? ", true);
  Dialog.addCheckbox("Retrieve data from EMI? ", true);
  Dialog.show();
  questions[0] = Dialog.getChoice();
  questions[1] = Dialog.getChoice();
  questions[2] = Dialog.getRadioButton();
  questions[3] = Dialog.getCheckbox();
  questions[4] = Dialog.getCheckbox();
  questions[5] = Dialog.getCheckbox();
  return questions;
}
//#####################################################//
function getTag(tag) {
  //get the needed tag

  info = getImageInfo();
  index1 = indexOf(info, tag);
  if (index1 == -1) return "";
  index1 = indexOf(info, "=", index1);
  if (index1 == -1) return "";
  index2 = indexOf(info, "\n", index1);
  value = substring(info, index1 + 1, index2);
  return value;
}
//#####################################################//
function crea_bar(ancho, pixel) {
  //function that prints the scalebar with certain width

  //first calculate the ideal width
  // it is a third of the size of one pixel times the number of pixels
  baseWidth = (ancho * pixel) / 3;
  scaleValues = newArray(1, 2, 3, 4, 5);
  oldWidth = 1;
  factor = 1;
  j = 0;
  for (t = 0; t < 20; t++) {
    scaleWidth = scaleValues[j] * factor;
    if (baseWidth > scaleWidth) {
      j++;
      oldWidth = scaleWidth;
      if (j >= scaleValues.length) {
        j = 0;
        factor *= 10;
      }
    } else {
      scaleWidth = oldWidth;
      if (scaleWidth > baseWidth) {
        scaleWidth = scaleWidth / 2;
      }

      t = 20;
    }
  }
  //then print it

  run(
    "Scale Bar...",
    "width=&scaleWidth height=8 font=50 color=White background=Black location=[Lower Right] bold"
  );
  return;
}