/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package bioformatsconverter;

import loci.formats.in.DefaultMetadataOptions;
import loci.formats.FormatException;
import loci.formats.out.OMETiffWriter;
import loci.formats.ome.OMEXMLMetadata;
import loci.formats.meta.MetadataRetrieve;
import loci.formats.meta.MetadataStore;
import loci.formats.MetadataTools;
import loci.formats.ImageReader;
import loci.formats.IFormatReader;
import loci.formats.ClassList;
import loci.formats.ChannelSeparator;
import loci.formats.out.APNGWriter;
import loci.formats.services.OMEXMLService;
import loci.formats.meta.IMetadata;
import loci.common.services.ServiceFactory;

import java.util.*;
import java.io.*;
import java.awt.image.*;
import java.awt.color.ColorSpace;
import loci.formats.in.MetadataLevel;
import ome.xml.model.primitives.PositiveFloat;
import ome.xml.model.primitives.PositiveInteger;

public class Main {
              
    static private boolean imageopen=false;
    static private String filename = "";
    static private boolean collectmeta = true;
    static private boolean collectmetaorig = false;
    static private boolean filtermeta = false;
    static private int savemode = 0;
    static private int stackmode = 0;

    public static void progress(int i, int size)
    {
        float prog = ( (float)(i+1)/(float)(size) )*100.0f;
        prog = Round(prog,2);

        System.out.print("\r\r      Progress = " + prog + " %");
        if(prog==100.0) System.out.println("\n");
    } 

    public static float Round(float Rval, int Rpl)
    {
        float p = (float)Math.pow(10,Rpl);
        Rval = Rval * p;
        float tmp = Math.round(Rval);
        
        return (float)tmp/p;
    }    
    public static void saveImageToOMETIFF(String in_fn, String out_dn) throws Exception
    {
        if(in_fn.length()==0)
        {
            System.out.println("\nERROR: Input filename is NULL!\n");
            return;
        }
        if(out_dn.length()==0)
        {
            System.out.println("\nERROR: Output dirname is NULL!\n");
            return;
        }

        FileOutputStream fos;
        DataOutputStream dos;
        String timeoutdirname;
        String channeloutdirname;

        //create a new MetadataStore
        ServiceFactory factory = new ServiceFactory();
        OMEXMLService service = factory.getInstance(OMEXMLService.class);
        IMetadata meta = service.createOMEXMLMetadata();

        //MetadataStore meta = MetadataTools.createOMEXMLMetadata();
        //DummyMetadata meta = new DummyMetadata();

        //Create a IFormatReader to read in our file and
        //tell it what image files we can read in.
        ClassList defaultClasses;
        defaultClasses = new ClassList("readers.txt", IFormatReader.class);
        IFormatReader  myimagereader = new ImageReader (defaultClasses);
        myimagereader.setMetadataOptions(new DefaultMetadataOptions(MetadataLevel.ALL));
        myimagereader.setOriginalMetadataPopulated(collectmetaorig);
        myimagereader.setMetadataFiltered(filtermeta);
        myimagereader.setMetadataStore(meta);
        myimagereader = new ChannelSeparator(myimagereader);

        //point the reader to our image file(s)
        myimagereader.setId(in_fn);

        //retrieve the metadata and save it in a OMEXLMMetaData object
        MetadataStore metarestore = (MetadataStore) myimagereader.getMetadataStore();
        MetadataRetrieve metaretrieve = (MetadataRetrieve) metarestore;

        FileWriter fstream;
        BufferedWriter out;

        //strip the original filename from it's extention
        //we will use this string for our directory names
        int index = in_fn.lastIndexOf("/");
        String infilname;
        if(index!=-1) infilname = in_fn.substring(index+1, in_fn.length());
        else infilname = in_fn;
        infilname = infilname.replace('.','_');

        System.out.println("Number of Images in Current File: " + myimagereader.getSeriesCount() + "\n");

        //get image dimensionality info
        int series = myimagereader.getSeriesCount();

        for(int s=0; s<series; s++)
        {
            int i=0;

            myimagereader.setSeries(s);

            //retrieve the metadata and save it in a OMEXLMMetaData object
            metarestore = (MetadataStore) myimagereader.getMetadataStore();
            metaretrieve = (MetadataRetrieve) metarestore;

             //generate the current timepoint string
            int sdigits = Integer.toString(s).length();
            String snumb = Integer.toString(s);
            if(sdigits==1) snumb = "S00"+snumb;
            else if(sdigits==2) snumb = "S0"+snumb;

            int numbimgs = myimagereader.getImageCount();
            int xres = (int)metaretrieve.getPixelsSizeX(s).getValue();//myimagereader.getSizeX();
            int yres = (int)metaretrieve.getPixelsSizeY(s).getValue();//myimagereader.getSizeY();
            int zres = metaretrieve.getPixelsSizeZ(s).getValue();//myimagereader.getSizeZ();
            int cres = metaretrieve.getPixelsSizeC(s).getValue();//myimagereader.getSizeC();
            int tres = metaretrieve.getPixelsSizeT(s).getValue();//myimagereader.getSizeT();

            PositiveFloat xsize, ysize, zsize;
            //xsize=ysize=zsize= new PositiveFloat(0.0);

            xsize = metaretrieve.getPixelsPhysicalSizeX(s);
            ysize = metaretrieve.getPixelsPhysicalSizeY(s);
            zsize = metaretrieve.getPixelsPhysicalSizeZ(s);

            String dimorder = myimagereader.getDimensionOrder();

            System.out.println("    Series: Image " + (s+1) + " of " + series);
            System.out.println("    =============================================");
            System.out.println("    Image INFO:");
            System.out.println("    (" + xres + "," + yres + "," + zres + ") (" + cres + "," + tres + ")" );
            System.out.println("    Number of images to save: "  + numbimgs);
            System.out.println("    Dimensions Order: " + dimorder);
            System.out.println("    (voxel size) X: " + xsize + " Y: " + ysize + " Z: " + zsize);
            System.out.println("    TimeStart: (sec) " + metaretrieve.getImageAcquiredDate(s));
            System.out.println("    TimeStep: (sec) " + metaretrieve.getPixelsTimeIncrement(s));
            System.out.println("    =============================================");
            System.out.println("    Saving to OME-TIFF...");
            
            for(int t=0; t<tres; t++)
            {
                System.out.println("Timepoint: " + t +" of " + tres);

                //generate a string for the current timepoint
                //and create a directory to store it in
                int tdigits = Integer.toString(t).length();
                String tnumb = Integer.toString(t);
                if(tdigits==1) tnumb = "00"+tnumb;
                else if(tdigits==2) tnumb = "0"+tnumb;
                timeoutdirname = out_dn + snumb + "_T" + tnumb + "/";
                (new File(timeoutdirname)).mkdir();

                for(int z=0; z<zres; z++)
                {
                    //generate a string for the current z
                    //to be used in the savefile name
                    int zdigits = Integer.toString(z).length();
                    String znumb = Integer.toString(z);
                    if(zdigits==1) znumb = "00"+znumb;
                    else if(zdigits==2) znumb = "0"+znumb;

                    progress(i, numbimgs);

                    for(int c=0; c<cres; c++)
                    {
                        //generate a string for the current channel
                        //and create a directory to store it in
                        int cdigits = Integer.toString(c).length();
                        String cnumb = Integer.toString(c);
                        if(cdigits==1) cnumb = "00"+cnumb;
                        else if(cdigits==2) cnumb = "0"+cnumb;
                        channeloutdirname = timeoutdirname + "C" + cnumb + "/";
                        (new File(channeloutdirname)).mkdir();

                        //generate a unique filename for the current image
                        String savefilename = channeloutdirname + infilname + "_T" + tnumb + "_Z" + znumb + "_C" + cnumb + ".tif";
                       // System.out.println("Saving file " + (i) +"/" + numbimgs + " index: " + myimagereader.getIndex(z,c,t) + " fn: " + savefilename);

                        //retrieve the current image in the file
                        byte[] imagebytes = myimagereader.openBytes(myimagereader.getIndex(z,c,t));

                        if(z==0)
                        {
                            //write the viewer friendly metadata in each directory
                            fstream = new FileWriter(channeloutdirname + "voxelscale.txt");
                            out = new BufferedWriter(fstream);
                            out.write("x " +  xsize);
                            out.newLine();
                            out.write("y " +  ysize);
                            out.newLine();
                            out.write("z " +  zsize);
                            out.newLine();
                            //Close the output stream
                            out.close();

                            fstream = new FileWriter(channeloutdirname + "voxelspacing.txt");
                            out = new BufferedWriter(fstream);
                            out.write("x " +  xsize);
                            out.newLine();
                            out.write("y " +  ysize);
                            out.newLine();
                            out.write("z " +  zsize);
                            out.newLine();
                            //Close the output stream
                            out.close();
                        }
                        
                        //update the metadata for this image
                        metarestore.setPixelsSizeX(new PositiveInteger(xres), 0);
                        metarestore.setPixelsSizeY(new PositiveInteger(yres), 0);
                        metarestore.setPixelsSizeZ(new PositiveInteger(1), 0);
                        metarestore.setPixelsSizeC(new PositiveInteger(1), 0);
                        metarestore.setPixelsSizeT(new PositiveInteger(1), 0);
                        metarestore.setPixelsPhysicalSizeX(xsize, 0);
                        metarestore.setPixelsPhysicalSizeY(ysize, 0);
                        metarestore.setPixelsPhysicalSizeZ(zsize, 0);

                        //create a new ometiffwriter object
                        //and set the associated metadata to it
                        OMETiffWriter ometiffwriter = new OMETiffWriter();
                        ometiffwriter.setMetadataRetrieve((MetadataRetrieve)metarestore);

                        //set the filename
                        ometiffwriter.setId(savefilename);

                        //write the image to disk
                        //saveImage(Image image, int series, boolean lastInSeries, boolean last)
                        ometiffwriter.saveBytes(0, imagebytes);
                        ometiffwriter.close();
                        i++;
                    }
                }
            }
        }
    }
    public static void saveImageToOMETIFF_Zstack(String in_fn, String out_dn) throws Exception
    {
        if(in_fn.length()==0)
        {
            System.out.println("\nERROR: Input filename is NULL!\n");        
            return;
        }
        if(out_dn.length()==0)
        {
            System.out.println("\nERROR: Output dirname is NULL!\n");        
            return;
        }
        
        //MetadataStore meta = MetadataTools.createOMEXMLMetadata();
        ServiceFactory factory = new ServiceFactory();
        OMEXMLService service = factory.getInstance(OMEXMLService.class);
        IMetadata meta = service.createOMEXMLMetadata();

        //setup what we can read/write.
        ClassList defaultClasses;
        defaultClasses = new ClassList("readers.txt", IFormatReader.class);

        System.out.println("Loading file: " + in_fn);
     
        //create an imagereader object.
        IFormatReader  myimagereader = new ImageReader (defaultClasses);
        myimagereader.setMetadataOptions(new DefaultMetadataOptions(MetadataLevel.ALL));
        myimagereader.setOriginalMetadataPopulated(collectmetaorig);
        myimagereader.setMetadataFiltered(filtermeta);
        myimagereader.setMetadataStore(meta);
        myimagereader = new ChannelSeparator(myimagereader);

        //point the reader to our image file(s)
        try{myimagereader.setId(in_fn);}
        catch(FormatException exc)
        {
            System.out.println(exc.toString());
            exc.printStackTrace();
        }
        catch (IOException exc)
        {
            System.out.println(exc.toString());
            exc.printStackTrace();
        }
        
        //retrieve the metadata and save it in a OMEXLMMetaData object
        MetadataStore metarestore = (MetadataStore) myimagereader.getMetadataStore();
        MetadataRetrieve metaretrieve = (MetadataRetrieve) metarestore;
        //OMEXMLMetadata omexmlmetadata = (OMEXMLMetadata) metarestore;
        
        //remove the extension from the source file
        //we will use this name for the generated saved stacks
        String infilname;
        int index = in_fn.lastIndexOf("/");      
        if(index!=-1) infilname = in_fn.substring(index+1, in_fn.length());
        else infilname = in_fn;        
        infilname = infilname.replace('.','_');

        System.out.println("Number of Images in Current File: " + myimagereader.getSeriesCount() + "\n");

        //get image dimensionality info
        int series = myimagereader.getSeriesCount();

        for(int s=0; s<series; s++)
        {
            int i=0;
            
            myimagereader.setSeries(s);

            //retrieve the metadata and save it in a OMEXLMMetaData object
            metarestore = (MetadataStore) myimagereader.getMetadataStore();
            metaretrieve = (MetadataRetrieve) metarestore;

             //generate the current timepoint string
            int sdigits = Integer.toString(s).length();
            String snumb = Integer.toString(s);
            if(sdigits==1) snumb = "S00"+snumb;
            else if(sdigits==2) snumb = "S0"+snumb;

            int numbimgs = myimagereader.getImageCount();
            int xres = (int)metaretrieve.getPixelsSizeX(s).getValue();//myimagereader.getSizeX();
            int yres = (int)metaretrieve.getPixelsSizeY(s).getValue();//myimagereader.getSizeY();
            int zres = metaretrieve.getPixelsSizeZ(s).getValue();//myimagereader.getSizeZ();
            int cres = metaretrieve.getPixelsSizeC(s).getValue();//myimagereader.getSizeC();
            int tres = metaretrieve.getPixelsSizeT(s).getValue();//myimagereader.getSizeT();
            
            PositiveFloat xsize, ysize, zsize;
            //xsize=ysize=zsize= new PositiveFloat(0.0);

            xsize = metaretrieve.getPixelsPhysicalSizeX(s);
            ysize = metaretrieve.getPixelsPhysicalSizeY(s);
            zsize = metaretrieve.getPixelsPhysicalSizeZ(s);

            String dimorder = myimagereader.getDimensionOrder();

            System.out.println("    Series: Image " + (s+1) + " of " + series);
            System.out.println("    =============================================");
            System.out.println("    Image INFO:");
            System.out.println("    (" + xres + "," + yres + "," + zres + ") (" + cres + "," + tres + ")" );
            System.out.println("    Number of images to save: "  + numbimgs);
            System.out.println("    Dimensions Order: " + dimorder);
            System.out.println("    (voxel size) X: " + xsize + " Y: " + ysize + " Z: " + zsize);
            System.out.println("    TimeStart: (sec) " + metaretrieve.getImageAcquiredDate(s));
            System.out.println("    TimeStep: (sec) " + metaretrieve.getPixelsTimeIncrement(s));
            System.out.println("    =============================================");
            System.out.println("    Saving to OME-TIFF...");

            for(int t=0; t<tres; t++)
            {
                System.out.println("Timepoint: " + t +" of " + tres);
                
                //generate the current timepoint string
                int tdigits = Integer.toString(t).length();
                String tnumb = Integer.toString(t);
                if(tdigits==1) tnumb = "T00"+tnumb;
                else if(tdigits==2) tnumb = "T0"+tnumb;

                for(int c=0; c<cres; c++)
                {
                    System.out.println("Channel: " + c +" of " + cres);

                    //generate the current channel string
                    int cdigits = Integer.toString(c).length();
                    String cnumb = Integer.toString(c);
                    if(cdigits==1) cnumb = "C00"+cnumb;
                    else if(cdigits==2) cnumb = "C0"+cnumb;

                    //now generate the file name for the current stack
                    String savefilename = out_dn + snumb + "_" + tnumb + "_" + cnumb + "_" + infilname + ".tiff";
                    //System.out.println("savefilename: " + savefilename + ".tiff");

                    //update the metadata for this image
                    metarestore.setPixelsSizeX(new PositiveInteger(xres), 0);
                    metarestore.setPixelsSizeY(new PositiveInteger(yres), 0);
                    metarestore.setPixelsSizeZ(new PositiveInteger(zres), 0);
                    metarestore.setPixelsSizeC(new PositiveInteger(1), 0);
                    metarestore.setPixelsSizeT(new PositiveInteger(1), 0);
                    metarestore.setPixelsPhysicalSizeX(xsize, 0);
                    metarestore.setPixelsPhysicalSizeY(ysize, 0);
                    metarestore.setPixelsPhysicalSizeZ(zsize, 0);

                    //create a new ometiffwriter object
                    //and set the associated metadata to it
                    OMETiffWriter ometiffwriter = new OMETiffWriter();
                    ometiffwriter.setMetadataRetrieve((MetadataRetrieve)metarestore);

                    //set the filename
                    ometiffwriter.setId(savefilename);

                    for(int z=0; z<zres; z++)
                    {
                        progress(i, numbimgs);

                        //retrieve the current image in the LSM file
                        byte[] imagebytes = myimagereader.openBytes(myimagereader.getIndex(z,c,t));

                        //write the image to disk
                        ometiffwriter.saveBytes(0, imagebytes);

                        i++;
                    }
                    ometiffwriter.close();
                }
            }
        }
    }
    public static void saveImageToOMETIFF_ZCstack(String in_fn, String out_dn) throws Exception
    {
        if(in_fn.length()==0)
        {
            System.out.println("\nERROR: Input filename is NULL!\n");
            return;
        }
        if(out_dn.length()==0)
        {
            System.out.println("\nERROR: Output dirname is NULL!\n");
            return;
        }

        //MetadataStore meta = MetadataTools.createOMEXMLMetadata();
        ServiceFactory factory = new ServiceFactory();
        OMEXMLService service = factory.getInstance(OMEXMLService.class);
        IMetadata meta = service.createOMEXMLMetadata();

        //setup what we can read/write.
        ClassList defaultClasses;
        defaultClasses = new ClassList("readers.txt", IFormatReader.class);

        //create an imagereader object.
        IFormatReader  myimagereader = new ImageReader (defaultClasses);
        myimagereader.setMetadataOptions(new DefaultMetadataOptions(MetadataLevel.ALL));
        myimagereader.setOriginalMetadataPopulated(collectmetaorig);
        myimagereader.setMetadataFiltered(filtermeta);
        myimagereader.setMetadataStore(meta);
        myimagereader = new ChannelSeparator(myimagereader);
        
        //point the reader to our image file(s)
        try{myimagereader.setId(in_fn);}
        catch(FormatException exc)
        {
            exc.printStackTrace();
        }
        catch (IOException exc)
        {
            exc.printStackTrace();
        }

        //retrieve the metadata and save it in a OMEXLMMetaData object
        MetadataStore metarestore = (MetadataStore) myimagereader.getMetadataStore();
        MetadataRetrieve metaretrieve = (MetadataRetrieve) metarestore;
        //OMEXMLMetadata omexmlmetadata = (OMEXMLMetadata) metarestore;

        System.out.println("Number of Images in Current File: " + myimagereader.getSeriesCount() + "\n");

        //get image dimensionality info
        int series = myimagereader.getSeriesCount();

        //remove the extension from the source file
        //we will use this name for the generated saved stacks
        String infilname;
        int index = in_fn.lastIndexOf("/");
        if(index!=-1) infilname = in_fn.substring(index+1, in_fn.length());
        else infilname = in_fn;
        infilname = infilname.replace('.','_');

        for(int s=0; s<series; s++)
        {
            //helpers
            int i=0;
            myimagereader.setSeries(s);

            //retrieve the metadata and save it in a OMEXLMMetaData object
            metarestore = (MetadataStore) myimagereader.getMetadataStore();
            metaretrieve = (MetadataRetrieve) metarestore;

             //generate the current timepoint string
            int sdigits = Integer.toString(s).length();
            String snumb = Integer.toString(s);
            if(sdigits==1) snumb = "S00"+snumb;
            else if(sdigits==2) snumb = "S0"+snumb;

            int numbimgs = myimagereader.getImageCount();
            int xres = (int)metaretrieve.getPixelsSizeX(s).getValue();//myimagereader.getSizeX();
            int yres = (int)metaretrieve.getPixelsSizeY(s).getValue();//myimagereader.getSizeY();
            int zres = metaretrieve.getPixelsSizeZ(s).getValue();//myimagereader.getSizeZ();
            int cres = metaretrieve.getPixelsSizeC(s).getValue();//myimagereader.getSizeC();
            int tres = metaretrieve.getPixelsSizeT(s).getValue();//myimagereader.getSizeT();
            int samples = metaretrieve.getChannelSamplesPerPixel(s, 0).getValue();

            PositiveFloat xsize, ysize, zsize;
            //xsize=ysize=zsize= new PositiveFloat(0.0);

            xsize = metaretrieve.getPixelsPhysicalSizeX(s);
            ysize = metaretrieve.getPixelsPhysicalSizeY(s);
            zsize = metaretrieve.getPixelsPhysicalSizeZ(s);

            String dimorder = myimagereader.getDimensionOrder();

            System.out.println("    Series: Image " + (s+1) + " of " + series);
            System.out.println("    =============================================");
            System.out.println("    Image INFO:");
            System.out.println("    (" + xres + "," + yres + "," + zres + ") (" + cres + "," + tres + ")" );
            System.out.println("    Samples per Channel: " + samples);
            System.out.println("    Number of images to save: "  + numbimgs);
            System.out.println("    Dimensions Order: " + dimorder);
            System.out.println("    (voxel size) X: " + xsize + " Y: " + ysize + " Z: " + zsize);
            System.out.println("    TimeStart: (sec) " + metaretrieve.getImageAcquiredDate(s));
            System.out.println("    TimeStep: (sec) " + metaretrieve.getPixelsTimeIncrement(s));
            System.out.println("    =============================================");
            System.out.println("    Saving to OME-TIFF...");

            for(int t=0; t<tres; t++)
            {
                System.out.println("Timepoint: " + t +" of " + tres);

                //generate the current timepoint string
                int tdigits = Integer.toString(t).length();
                String tnumb = Integer.toString(t);
                if(tdigits==1) tnumb = "T00"+tnumb;
                else if(tdigits==2) tnumb = "T0"+tnumb;

                //now generate the file name for the current stack
                String savefilename = out_dn + snumb + "_" + tnumb + "_" + infilname + ".tiff";

                //update the metadata for this image
                metarestore.setPixelsSizeX(new PositiveInteger(xres), 0);
                metarestore.setPixelsSizeY(new PositiveInteger(yres), 0);
                metarestore.setPixelsSizeZ(new PositiveInteger(zres), 0);
                metarestore.setPixelsSizeC(new PositiveInteger(cres), 0);
                metarestore.setPixelsSizeT(new PositiveInteger(1), 0);
                metarestore.setPixelsPhysicalSizeX(xsize, 0);
                metarestore.setPixelsPhysicalSizeY(ysize, 0);
                metarestore.setPixelsPhysicalSizeZ(zsize, 0);
               // metarestore.setChannelSamplesPerPixel(new PositiveInteger(cres), 0, 0);

                //create a new ometiffwriter object
                //and set the associated metadata to it
                OMETiffWriter ometiffwriter = new OMETiffWriter();
                ometiffwriter.setMetadataRetrieve((MetadataRetrieve)metarestore);

                //set the filename
                ometiffwriter.setId(savefilename);

                for(int z=0; z<zres; z++)
                {
                    progress(i, numbimgs);

                    byte[] allchannelsimagebytes = new byte[xres*yres*cres];
                    for(int c=0; c<cres; c++)
                    {
                        byte[] imagebytes = myimagereader.openBytes(myimagereader.getIndex(z,c,t));

                        int offset=0;
                        for(int kk=0; kk<imagebytes.length; kk++)
                        {
                            offset=(xres*yres)*c;
                            allchannelsimagebytes[offset+kk] = imagebytes[kk];
                        }

                        //ometiffwriter.saveBytes(c*zres+z, imagebytes);
                        i++;
                    }

                    //write the image to disk
                    ometiffwriter.saveBytes(0, allchannelsimagebytes);
                }
                ometiffwriter.close();
            }
        }
    }
    public static void saveImageToOMETIFF_ZCTstack(String in_fn, String out_dn) throws Exception
    {
        if(in_fn.length()==0)
        {
            System.out.println("\nERROR: Input filename is NULL!\n");
            return;
        }
        if(out_dn.length()==0)
        {
            System.out.println("\nERROR: Output dirname is NULL!\n");
            return;
        }

        //MetadataStore meta = MetadataTools.createOMEXMLMetadata();
        ServiceFactory factory = new ServiceFactory();
        OMEXMLService service = factory.getInstance(OMEXMLService.class);
        IMetadata meta = service.createOMEXMLMetadata();

        //setup what we can read/write.
        ClassList defaultClasses;
        defaultClasses = new ClassList("readers.txt", IFormatReader.class);

        //create an imagereader object.
        IFormatReader  myimagereader = new ImageReader (defaultClasses);
        myimagereader.setMetadataOptions(new DefaultMetadataOptions(MetadataLevel.ALL));
        myimagereader.setOriginalMetadataPopulated(collectmetaorig);
        myimagereader.setMetadataFiltered(filtermeta);
        myimagereader.setMetadataStore(meta);
        myimagereader = new ChannelSeparator(myimagereader);

        //point the reader to our image file(s)
        try{myimagereader.setId(in_fn);}
        catch(FormatException exc)
        {
            exc.printStackTrace();
        }
        catch (IOException exc)
        {
            exc.printStackTrace();
        }

        //retrieve the metadata and save it in a OMEXLMMetaData object
        MetadataStore metarestore = (MetadataStore) myimagereader.getMetadataStore();
        MetadataRetrieve metaretrieve = (MetadataRetrieve) metarestore;
        //OMEXMLMetadata omexmlmetadata = (OMEXMLMetadata) metarestore;
     
        System.out.println("Number of Images in Current File: " + myimagereader.getSeriesCount() + "\n");

        //get image dimensionality info
        int series = myimagereader.getSeriesCount();

        for(int s=0; s<series; s++)
        {
            //helpers
            boolean eostack = false;
            int i=0;
            
            myimagereader.setSeries(s);

            //retrieve the metadata and save it in a OMEXLMMetaData object
            metarestore = (MetadataStore) myimagereader.getMetadataStore();
            metaretrieve = (MetadataRetrieve) metarestore;

             //generate the current timepoint string
            int sdigits = Integer.toString(s).length();
            String snumb = Integer.toString(s);
            if(sdigits==1) snumb = "S00"+snumb;
            else if(sdigits==2) snumb = "S0"+snumb;

            int numbimgs = myimagereader.getImageCount();
            int xres = (int)metaretrieve.getPixelsSizeX(s).getValue();//myimagereader.getSizeX();
            int yres = (int)metaretrieve.getPixelsSizeY(s).getValue();//myimagereader.getSizeY();
            int zres = metaretrieve.getPixelsSizeZ(s).getValue();//myimagereader.getSizeZ();
            int cres = metaretrieve.getPixelsSizeC(s).getValue();//myimagereader.getSizeC();
            int tres = metaretrieve.getPixelsSizeT(s).getValue();//myimagereader.getSizeT();
            int samples = metaretrieve.getChannelSamplesPerPixel(s, 0).getValue();

            PositiveFloat xsize, ysize, zsize;
            //xsize=ysize=zsize= new PositiveFloat(0.0);

            xsize = metaretrieve.getPixelsPhysicalSizeX(s);
            ysize = metaretrieve.getPixelsPhysicalSizeY(s);
            zsize = metaretrieve.getPixelsPhysicalSizeZ(s);

            String dimorder = myimagereader.getDimensionOrder();

            System.out.println("    Series: Image " + (s+1) + " of " + series);
            System.out.println("    =============================================");
            System.out.println("    Image INFO:");
            System.out.println("    (" + xres + "," + yres + "," + zres + ") (" + cres + "," + tres + ")" );
            System.out.println("    Number of images to save: "  + numbimgs);
            System.out.println("    Dimensions Order: " + dimorder);
            System.out.println("    (voxel size) X: " + xsize + " Y: " + ysize + " Z: " + zsize);
            System.out.println("    TimeStart: (sec) " + metaretrieve.getImageAcquiredDate(s));
            System.out.println("    TimeStep: (sec) " + metaretrieve.getPixelsTimeIncrement(s));
            System.out.println("    =============================================");
            System.out.println("    Saving to OME-TIFF...");

            //remove the extension from the source file
            //we will use this name for the generated saved stacks
            String infilname;
            int index = in_fn.lastIndexOf("/");
            if(index!=-1) infilname = in_fn.substring(index+1, in_fn.length());
            else infilname = in_fn;
            infilname = infilname.replace('.','_');

            //now generate the file name for the current stack
            String savefilename = out_dn + snumb + "_" + infilname + ".tiff";

            //update the metadata for this image
            metarestore.setPixelsSizeX(new PositiveInteger(xres), 0);
            metarestore.setPixelsSizeY(new PositiveInteger(yres), 0);
            metarestore.setPixelsSizeZ(new PositiveInteger(zres), 0);
            metarestore.setPixelsSizeC(new PositiveInteger(cres), 0);
            metarestore.setPixelsSizeT(new PositiveInteger(tres), 0);
            metarestore.setPixelsPhysicalSizeX(xsize, 0);
            metarestore.setPixelsPhysicalSizeY(ysize, 0);
            metarestore.setPixelsPhysicalSizeZ(zsize, 0);
            metarestore.setChannelSamplesPerPixel(new PositiveInteger(1), 0, 0);

            //create a new ometiffwriter object
            //and set the associated metadata to it
            OMETiffWriter ometiffwriter = new OMETiffWriter();
            ometiffwriter.setMetadataRetrieve((MetadataRetrieve)metarestore);

            //set the filename
            ometiffwriter.setId(savefilename);
            for(int t=0; t<tres; t++)
            {
                System.out.println("Timepoint: " + t +" of " + tres);

                for(int z=0; z<zres; z++)
                {
                    progress(i, numbimgs);

                    byte[] allchannelsimagebytes = new byte[xres*yres*cres];
                    for(int c=0; c<cres; c++)
                    {
                        byte[] imagebytes = myimagereader.openBytes(myimagereader.getIndex(z,c,t));

                        int offset=0;
                        for(int kk=0; kk<imagebytes.length; kk++)
                        {
                            offset=(xres*yres)*c;
                            allchannelsimagebytes[offset+kk] = imagebytes[kk];
                        }

                        //ometiffwriter.saveBytes(c*zres+z, imagebytes);
                        i++;
                    }

                    //write the image to disk
                    //ometiffwriter.saveBytes(imagebytes, eostack);
                    ometiffwriter.saveBytes(0, allchannelsimagebytes);
                }
            }
        }
    }

    public static void saveImageToPNG_singlechannel(String in_fn, String out_dn) throws Exception
    {
        if(in_fn.length()==0)
        {
            System.out.println("\nERROR: Input filename is NULL!\n");
            return;
        }
        if(out_dn.length()==0)
        {
            System.out.println("\nERROR: Output dirname is NULL!\n");
            return;
        }

        FileOutputStream fos;
        DataOutputStream dos;
        String timeoutdirname;
        String channeloutdirname;

        System.out.println("Loading file: " + in_fn);

        //MetadataStore meta = MetadataTools.createOMEXMLMetadata();
        ServiceFactory factory = new ServiceFactory();
        OMEXMLService service = factory.getInstance(OMEXMLService.class);
        IMetadata meta = service.createOMEXMLMetadata();

        //Create a IFormatReader to read in our file and
        //tell it what image files we can read in.
        ClassList defaultClasses;
        defaultClasses = new ClassList("readers.txt", IFormatReader.class);
        IFormatReader  myimagereader = new ImageReader (defaultClasses);
        //myimagereader.setMetadataCollected(collectmeta);
        myimagereader.setOriginalMetadataPopulated(collectmetaorig);
        myimagereader.setMetadataFiltered(filtermeta);
        myimagereader.setMetadataStore(meta);
        myimagereader = new ChannelSeparator(myimagereader);

        //point the reader to our image file(s)
        myimagereader.setId(in_fn);

        //retrieve the metadata and save it in a OMEXLMMetaData object
        MetadataRetrieve metaretrieve = (MetadataRetrieve) myimagereader.getMetadataStore();
        MetadataStore metarestore = (MetadataStore) myimagereader.getMetadataStore();
        OMEXMLMetadata omexmlmetadata = (OMEXMLMetadata) metaretrieve;
        //System.out.println(omexmlmetadata.dumpXML());

        //strip the original filename from it's extention
        //we will use this string for our directory names
        int index = in_fn.lastIndexOf("/");
        String infilname;
        if(index!=-1) infilname = in_fn.substring(index+1, in_fn.length());
        else infilname = in_fn;
        infilname = infilname.replace('.','_');

        //create a buffered image
        BufferedImage buffimage = null;
        int i=0;

        System.out.println("Number of Images in Current File: " + myimagereader.getSeriesCount());

        //get image dimensionality info
        int series = myimagereader.getSeriesCount();

        for(int s=0; s<series; s++)
        {
            myimagereader.setSeries(s);

            //retrieve the metadata and save it in a OMEXLMMetaData object
            metarestore = myimagereader.getMetadataStore();
            metaretrieve = (MetadataRetrieve) metarestore;

             //generate the current timepoint string
            int sdigits = Integer.toString(s).length();
            String snumb = Integer.toString(s);
            if(sdigits==1) snumb = "S00"+snumb;
            else if(sdigits==2) snumb = "S0"+snumb;
           // snumb = snumb + "/" + snumb;
           // (new File(snumb + "/" )).mkdir();

            int numbimgs = myimagereader.getImageCount();
            int xres = (int)metaretrieve.getPixelsSizeX(s).getValue();//myimagereader.getSizeX();
            int yres = (int)metaretrieve.getPixelsSizeY(s).getValue();//myimagereader.getSizeY();
            int zres = metaretrieve.getPixelsSizeZ(s).getValue();//myimagereader.getSizeZ();
            int cres = metaretrieve.getPixelsSizeC(s).getValue();//myimagereader.getSizeC();
            int tres = metaretrieve.getPixelsSizeT(s).getValue();//myimagereader.getSizeT();
            int samples = metaretrieve.getChannelSamplesPerPixel(s, 0).getValue();
            ome.xml.model.enums.PixelType type = metaretrieve.getPixelsType(0);

            PositiveFloat xsize, ysize, zsize;
            //xsize=ysize=zsize= new PositiveFloat(0.0);

            xsize = metaretrieve.getPixelsPhysicalSizeX(s);
            ysize = metaretrieve.getPixelsPhysicalSizeY(s);
            zsize = metaretrieve.getPixelsPhysicalSizeZ(s);

            String dimorder = myimagereader.getDimensionOrder();

            System.out.println("    Series Image " + (s+1) + " of " + series);
            System.out.println("    =============================================");
            System.out.println("    Image INFO:");
            System.out.println("    (" + xres + "," + yres + "," + zres + ") (" + cres + "," + tres + ")" );
            System.out.println("    Channel Samples: " + samples );
            System.out.println("    Number of images to save: "  + numbimgs);
            System.out.println("    Dimensions Order: " + dimorder);
            System.out.println("    (voxel size) X: " + xsize + " Y: " + ysize + " Z: " + zsize);
            System.out.println("    TimeStart: (sec) " + metaretrieve.getImageAcquiredDate(s));
            System.out.println("    TimeStep: (sec) " + metaretrieve.getPixelsTimeIncrement(s));

            if(type==ome.xml.model.enums.PixelType.UINT8) System.out.println("    PixelType: UINT8");
            if(type==ome.xml.model.enums.PixelType.UINT16) System.out.println("    PixelType: UINT16");
            if(type==ome.xml.model.enums.PixelType.UINT32) System.out.println("    PixelType: UINT32");
            if(type==ome.xml.model.enums.PixelType.INT8) System.out.println("    PixelType: INT8");
            if(type==ome.xml.model.enums.PixelType.INT16) System.out.println("    PixelType: INT16");
            if(type==ome.xml.model.enums.PixelType.INT32) System.out.println("    PixelType: INT32");
            if(type==ome.xml.model.enums.PixelType.FLOAT) System.out.println("    PixelType: FLOAT");
            if(type==ome.xml.model.enums.PixelType.DOUBLE) System.out.println("    PixelType: DOUBLE");
            if(type==ome.xml.model.enums.PixelType.DOUBLECOMPLEX) System.out.println("    PixelType: DOUBLECOMPLEX");
            if(type==ome.xml.model.enums.PixelType.BIT) System.out.println("    PixelType: BIT");

            System.out.println("    =============================================");
            System.out.println("    Saving to PNG...");

            for(int t=0; t<tres; t++)
            {
                System.out.println("Timepoint: " + t +" of " + tres);

                //generate a string for the current timepoint
                //and create a directory to store it in
                int tdigits = Integer.toString(t).length();
                String tnumb = Integer.toString(t);
                if(tdigits==1) tnumb = "00"+tnumb;
                else if(tdigits==2) tnumb = "0"+tnumb;

                for(int z=0; z<zres; z++)
                {
                    //generate a string for the current z
                    //to be used in the savefile name
                    int zdigits = Integer.toString(z).length();
                    String znumb = Integer.toString(z);
                    if(zdigits==1) znumb = "00"+znumb;
                    else if(zdigits==2) znumb = "0"+znumb;

                    progress(z, zres);

                    byte[] allchannelsimagebytes;
                    allchannelsimagebytes = new byte[xres*yres*3];


                    for(int c=0; c<cres; c++)
                    {
                         for(int kkk=0; kkk<allchannelsimagebytes.length; kkk++)
                            allchannelsimagebytes[kkk]=0;

                        int cdigits = Integer.toString(c).length();
                        String cnumb = Integer.toString(c);
                        if(cdigits==1) cnumb = "00"+cnumb;
                        else if(cdigits==2) cnumb = "0"+cnumb;

                        byte[] imagebytes = myimagereader.openBytes(myimagereader.getIndex(z,c,t));;

                        //System.out.println("size: " + imagebytes.length);

                        int offset=0;
                        int helper=0;
                        for(int kk=0; kk<allchannelsimagebytes.length/3; kk++)
                        {
                            offset=0;

                            if(type==ome.xml.model.enums.PixelType.UINT8 || type==ome.xml.model.enums.PixelType.INT8)
                            {
                                offset=0;
                                allchannelsimagebytes[offset+kk] = imagebytes[kk];
                                offset=xres*yres*1;
                                allchannelsimagebytes[offset+kk] = imagebytes[kk];
                                offset=xres*yres*2;
                                allchannelsimagebytes[offset+kk] = imagebytes[kk];
                            }
                            else if(type==ome.xml.model.enums.PixelType.UINT16 || type==ome.xml.model.enums.PixelType.INT16)
                            {
                                //int value = (0xff & imagebytes[kk]) << 8 | (0xff & imagebytes[kk+1]) << 0;

                                //long value = 0;
                                int value = 0;
                                value = imagebytes[2*kk];
                                value <<= 8;
                                value += imagebytes[2*kk+1];

                                value += 65535/2.0;
                              //  if(value>65535) System.out.println(value);
                              //  if(value<0) System.out.println(value);
                               // value = 65535;
                                //System.out.println("value 16bit: " + (value));
                                //System.out.println("value 8bit: " + (value/65535.0)*255.0);
                                offset=0;
                                allchannelsimagebytes[offset+kk] = (byte)(((value/65535.0)*255.0));
                                offset=xres*yres*1;
                                allchannelsimagebytes[offset+kk] = (byte)(((value/65535.0)*255.0));
                                offset=xres*yres*2;
                                allchannelsimagebytes[offset+kk] = (byte)(((value/65535.0)*255.0));
                                //((value/65535.0)*255.0);
                                //allchannelsimagebytes[kk+(xres*yres)*1] = (byte)(0);//((value/65535.0)*255.0);
                                //allchannelsimagebytes[kk+(xres*yres)*2] = (byte)(0);//((value/65535.0)*255.0);
                            }
                            else
                            {
                                System.out.println("UNSUPPORTED DATA FORMAT!");
                            }
                        }

                        //ometiffwriter.saveBytes(c*zres+z, imagebytes);
                        i++;

                        timeoutdirname = out_dn + infilname + "_" + snumb + "_T" + tnumb+ "_C" + cnumb;
                       (new File(timeoutdirname + "/")).mkdir();

                        //generate a unique filename for the current image
                        String savefilename = timeoutdirname + "/" + infilname + "_" + snumb + "_T" + tnumb + "_C" + cnumb + "_Z" + znumb + ".png";

                        if(z==0)
                        {
                            //write the viewer friendly metadata in each directory
                            FileWriter fstream = new FileWriter(timeoutdirname + "/" + "voxelscale.txt");
                            BufferedWriter out = new BufferedWriter(fstream);
                            out.write("x " +  xsize);
                            out.newLine();
                            out.write("y " +  ysize);
                            out.newLine();
                            out.write("z " +  zsize);
                            out.newLine();
                            //Close the output stream
                            out.close();

                            fstream = new FileWriter(timeoutdirname + "/" + "voxelspacing.txt");
                            out = new BufferedWriter(fstream);
                            out.write("x " +  xsize);
                            out.newLine();
                            out.write("y " +  ysize);
                            out.newLine();
                            out.write("z " +  zsize);
                            out.newLine();
                            //Close the output stream
                            out.close();
                        }

                        //============================================
                        //Save the file as a PNG.
                        //============================================
                        metarestore.setPixelsSizeX(new PositiveInteger(xres), 0);
                        metarestore.setPixelsSizeY(new PositiveInteger(yres), 0);
                        metarestore.setPixelsSizeZ(new PositiveInteger(1), 0);
                        metarestore.setPixelsSizeC(new PositiveInteger(3), 0);
                        metarestore.setPlaneTheT(new PositiveInteger(1), 0, 0);
                        metarestore.setPlaneTheZ(new PositiveInteger(1), 0, 0);
                        metarestore.setChannelSamplesPerPixel(new PositiveInteger(3), 0, 0);
                        metarestore.setPixelsType(ome.xml.model.enums.PixelType.UINT8, 0);

                        APNGWriter pngwriter = new APNGWriter();
                        pngwriter.setMetadataRetrieve((MetadataRetrieve)metarestore);
                        pngwriter.setColorModel(ColorModel.getRGBdefault());
                        //pngwriter.setInterleaved(true);
                        pngwriter.setId(savefilename);
                        pngwriter.saveBytes(0, allchannelsimagebytes);
                        pngwriter.close();

                    }
                }
            }
        }
    }

    public static void saveImageToPNG_multichannel(String in_fn, String out_dn) throws Exception
    {
        if(in_fn.length()==0)
        {
            System.out.println("\nERROR: Input filename is NULL!\n");
            return;
        }
        if(out_dn.length()==0)
        {
            System.out.println("\nERROR: Output dirname is NULL!\n");
            return;
        }

        FileOutputStream fos;
        DataOutputStream dos;
        String timeoutdirname;
        String channeloutdirname;

        System.out.println("Loading file: " + in_fn);

        //MetadataStore meta = MetadataTools.createOMEXMLMetadata();
        ServiceFactory factory = new ServiceFactory();
        OMEXMLService service = factory.getInstance(OMEXMLService.class);
        IMetadata meta = service.createOMEXMLMetadata();

        //Create a IFormatReader to read in our file and
        //tell it what image files we can read in.
        ClassList defaultClasses;
        defaultClasses = new ClassList("readers.txt", IFormatReader.class);
        IFormatReader  myimagereader = new ImageReader (defaultClasses);
        //myimagereader.setMetadataCollected(collectmeta);
        myimagereader.setOriginalMetadataPopulated(collectmetaorig);
        myimagereader.setMetadataFiltered(filtermeta);
        myimagereader.setMetadataStore(meta);
        myimagereader = new ChannelSeparator(myimagereader);

        //point the reader to our image file(s)
        myimagereader.setId(in_fn);

        //retrieve the metadata and save it in a OMEXLMMetaData object
        MetadataRetrieve metaretrieve = (MetadataRetrieve) myimagereader.getMetadataStore();
        MetadataStore metarestore = (MetadataStore) myimagereader.getMetadataStore();
        OMEXMLMetadata omexmlmetadata = (OMEXMLMetadata) metaretrieve;
        //System.out.println(omexmlmetadata.dumpXML());

        //strip the original filename from it's extention
        //we will use this string for our directory names
        int index = in_fn.lastIndexOf("/");
        String infilname;
        if(index!=-1) infilname = in_fn.substring(index+1, in_fn.length());
        else infilname = in_fn;
        infilname = infilname.replace('.','_');

        //create a buffered image
        BufferedImage buffimage = null;
        int i=0;

        System.out.println("Number of Images in Current File: " + myimagereader.getSeriesCount());

        //get image dimensionality info
        int series = myimagereader.getSeriesCount();

        for(int s=0; s<series; s++)
        {
            myimagereader.setSeries(s);

            //retrieve the metadata and save it in a OMEXLMMetaData object
            metarestore = myimagereader.getMetadataStore();
            metaretrieve = (MetadataRetrieve) metarestore;

             //generate the current timepoint string
            int sdigits = Integer.toString(s).length();
            String snumb = Integer.toString(s);
            if(sdigits==1) snumb = "S00"+snumb;
            else if(sdigits==2) snumb = "S0"+snumb;
           // snumb = snumb + "/" + snumb;
           // (new File(snumb + "/" )).mkdir();
            
            int numbimgs = myimagereader.getImageCount();
            int xres = (int)metaretrieve.getPixelsSizeX(s).getValue();//myimagereader.getSizeX();
            int yres = (int)metaretrieve.getPixelsSizeY(s).getValue();//myimagereader.getSizeY();
            int zres = metaretrieve.getPixelsSizeZ(s).getValue();//myimagereader.getSizeZ();
            int cres = metaretrieve.getPixelsSizeC(s).getValue();//myimagereader.getSizeC();
            int tres = metaretrieve.getPixelsSizeT(s).getValue();//myimagereader.getSizeT();
            int samples = metaretrieve.getChannelSamplesPerPixel(s, 0).getValue();
            ome.xml.model.enums.PixelType type = metaretrieve.getPixelsType(0);

            PositiveFloat xsize, ysize, zsize;
            //xsize=ysize=zsize= new PositiveFloat(0.0);

            xsize = metaretrieve.getPixelsPhysicalSizeX(s);
            ysize = metaretrieve.getPixelsPhysicalSizeY(s);
            zsize = metaretrieve.getPixelsPhysicalSizeZ(s);

            String dimorder = myimagereader.getDimensionOrder();

            System.out.println("    Series Image " + (s+1) + " of " + series);
            System.out.println("    =============================================");
            System.out.println("    Image INFO:");
            System.out.println("    (" + xres + "," + yres + "," + zres + ") (" + cres + "," + tres + ")" );
            System.out.println("    Channel Samples: " + samples );
            System.out.println("    Number of images to save: "  + numbimgs);
            System.out.println("    Dimensions Order: " + dimorder);
            System.out.println("    (voxel size) X: " + xsize + " Y: " + ysize + " Z: " + zsize);
            System.out.println("    TimeStart: (sec) " + metaretrieve.getImageAcquiredDate(s));
            System.out.println("    TimeStep: (sec) " + metaretrieve.getPixelsTimeIncrement(s));

            if(type==ome.xml.model.enums.PixelType.UINT8) System.out.println("    PixelType: UINT8");
            if(type==ome.xml.model.enums.PixelType.UINT16) System.out.println("    PixelType: UINT16");
            if(type==ome.xml.model.enums.PixelType.UINT32) System.out.println("    PixelType: UINT32");
            if(type==ome.xml.model.enums.PixelType.INT8) System.out.println("    PixelType: INT8");
            if(type==ome.xml.model.enums.PixelType.INT16) System.out.println("    PixelType: INT16");
            if(type==ome.xml.model.enums.PixelType.INT32) System.out.println("    PixelType: INT32");
            if(type==ome.xml.model.enums.PixelType.FLOAT) System.out.println("    PixelType: FLOAT");
            if(type==ome.xml.model.enums.PixelType.DOUBLE) System.out.println("    PixelType: DOUBLE");
            if(type==ome.xml.model.enums.PixelType.DOUBLECOMPLEX) System.out.println("    PixelType: DOUBLECOMPLEX");
            if(type==ome.xml.model.enums.PixelType.BIT) System.out.println("    PixelType: BIT");

            System.out.println("    =============================================");
            System.out.println("    Saving to PNG...");

            for(int t=0; t<tres; t++)
            {
                System.out.println("Timepoint: " + t +" of " + tres);

                //generate a string for the current timepoint
                //and create a directory to store it in
                int tdigits = Integer.toString(t).length();
                String tnumb = Integer.toString(t);
                if(tdigits==1) tnumb = "00"+tnumb;
                else if(tdigits==2) tnumb = "0"+tnumb;
                timeoutdirname = out_dn + infilname + "_" + snumb + "_T" + tnumb;
                (new File(timeoutdirname)).mkdir();

                for(int z=0; z<zres; z++)
                {
                    //generate a string for the current z
                    //to be used in the savefile name
                    int zdigits = Integer.toString(z).length();
                    String znumb = Integer.toString(z);
                    if(zdigits==1) znumb = "00"+znumb;
                    else if(zdigits==2) znumb = "0"+znumb;

                    progress(z, zres);

                    byte[] allchannelsimagebytes;
                    allchannelsimagebytes = new byte[xres*yres*3];

                    for(int kkk=0; kkk<allchannelsimagebytes.length; kkk++)
                        allchannelsimagebytes[kkk]=0;
                    
                    for(int c=0; c<cres; c++)
                    {
                        byte[] imagebytes = myimagereader.openBytes(myimagereader.getIndex(z,c,t));;

                        //System.out.println("size: " + imagebytes.length);

                        int offset=0;
                        int helper=0;
                        for(int kk=0; kk<allchannelsimagebytes.length/3; kk++)
                        {
                            offset=xres*yres*c;
                            
                            if(type==ome.xml.model.enums.PixelType.UINT8 || type==ome.xml.model.enums.PixelType.INT8)
                            {
                                allchannelsimagebytes[offset+kk] = imagebytes[kk];
                            }
                            else if(type==ome.xml.model.enums.PixelType.UINT16 || type==ome.xml.model.enums.PixelType.INT16)
                            {
                                //int value = (0xff & imagebytes[kk]) << 8 | (0xff & imagebytes[kk+1]) << 0;

                                //long value = 0;
                                int value = 0;
                                value = imagebytes[2*kk];
                                value <<= 8;
                                value += imagebytes[2*kk+1];

                                value += 65535/2.0;
                              //  if(value>65535) System.out.println(value);
                              //  if(value<0) System.out.println(value);
                               // value = 65535;
                                //System.out.println("value 16bit: " + (value));
                                //System.out.println("value 8bit: " + (value/65535.0)*255.0);
                                allchannelsimagebytes[offset+kk] = (byte)(((value/65535.0)*255.0));
                                //((value/65535.0)*255.0);
                                //allchannelsimagebytes[kk+(xres*yres)*1] = (byte)(0);//((value/65535.0)*255.0);
                                //allchannelsimagebytes[kk+(xres*yres)*2] = (byte)(0);//((value/65535.0)*255.0);
                            }
                            else
                            {
                                System.out.println("UNSUPPORTED DATA FORMAT!");
                            }
                        }

                        //ometiffwriter.saveBytes(c*zres+z, imagebytes);
                        i++;
                    }
                   (new File(timeoutdirname + "/")).mkdir();

                    //generate a unique filename for the current image
                    String savefilename = timeoutdirname + "/" + infilname + "_" + snumb + "_T" + tnumb + "_Z" + znumb + ".png";
 
                    if(z==0)
                    {
                        //write the viewer friendly metadata in each directory
                        FileWriter fstream = new FileWriter(timeoutdirname + "/" + "voxelscale.txt");
                        BufferedWriter out = new BufferedWriter(fstream);
                        out.write("x " +  xsize);
                        out.newLine();
                        out.write("y " +  ysize);
                        out.newLine();
                        out.write("z " +  zsize);
                        out.newLine();
                        //Close the output stream
                        out.close();

                        fstream = new FileWriter(timeoutdirname + "/" + "voxelspacing.txt");
                        out = new BufferedWriter(fstream);
                        out.write("x " +  xsize);
                        out.newLine();
                        out.write("y " +  ysize);
                        out.newLine();
                        out.write("z " +  zsize);
                        out.newLine();
                        //Close the output stream
                        out.close();
                    }

                    //============================================
                    //Save the file as a PNG.
                    //============================================
                    metarestore.setPixelsSizeX(new PositiveInteger(xres), 0);
                    metarestore.setPixelsSizeY(new PositiveInteger(yres), 0);
                    metarestore.setPixelsSizeZ(new PositiveInteger(1), 0);
                    metarestore.setPixelsSizeC(new PositiveInteger(3), 0);
                    metarestore.setPlaneTheC(new PositiveInteger(3), 0, 0);
                    metarestore.setPlaneTheT(new PositiveInteger(1), 0, 0);
                    metarestore.setPlaneTheZ(new PositiveInteger(1), 0, 0);
                    metarestore.setChannelSamplesPerPixel(new PositiveInteger(3), 0, 0);
                    metarestore.setPixelsType(ome.xml.model.enums.PixelType.UINT8, 0);
                    
                    APNGWriter pngwriter = new APNGWriter();
                    pngwriter.setMetadataRetrieve((MetadataRetrieve)metarestore);
                    pngwriter.setColorModel(ColorModel.getRGBdefault());
                    //pngwriter.setInterleaved(true);
                    pngwriter.setId(savefilename);
                    pngwriter.saveBytes(0, allchannelsimagebytes);
                    pngwriter.close();
                }
            }
        }
    }   
    public static void readSettings(String fn)
    {
        File aFile = new File(fn);
        String filecontents = new String();
        filecontents = "";

        try
        {
            //use buffering, reading one line at a time
            //FileReader always assumes default encoding is OK!
            BufferedReader input =  new BufferedReader(new FileReader(aFile));
            try
            {
                String line = null; //not declared within while loop
                /*
                * readLine is a bit quirky :
                * it returns the content of a line MINUS the newline.
                * it returns null only for the END of the stream.
                * it returns an empty String if two newlines appear in a row.
                */
                while (( line = input.readLine()) != null)
                {
                    filecontents = filecontents+"\r\n"+line;
                }
            }
            finally
            {
                input.close();
            }
         }
            catch (IOException ex)
         {
            System.out.println("ERROR: Settings.txt file could not be found!");
         }

        //System.out.println("file: " + filecontents);

        StringTokenizer st = new StringTokenizer(filecontents);
        String token;
        while (st.hasMoreTokens())
        {
            token = st.nextToken();
            //System.out.println(token);
            
            if(token.equals("savemode:"))
            {
                token = st.nextToken();
                if(token.equals("TIFF"))
                {
                    System.out.println("savemode: TIFF");
                    savemode = 1;
                }
                else if(token.equals("PNG"))
                {
                    System.out.println("savemode: PNG");
                    savemode = 2;
                }
            }
            else if(token.equals("stackmode:"))
            {
                token = st.nextToken();
                if(token.equals("SINGLE_TIFFS"))
                {
                    System.out.println("tiffmode: single tiffs");
                    stackmode = 1;
                }
                else if(token.equals("Z_STACK_TIFFS"))
                {
                    System.out.println("tiffmode: Z_STACK tiffs");
                    stackmode = 2;
                }
                else if(token.equals("ZC_STACK_TIFFS"))
                {
                    System.out.println("tiffmode: ZC_STACK tiffs");
                    stackmode = 3;
                }
                else if(token.equals("ZCT_STACK_TIFFS"))
                {
                    System.out.println("tiffmode: ZCT_STACK tiffs");
                    stackmode = 4;
                }
                else if(token.equals("SINGLE_PNG"))
                {
                    System.out.println("pngmode: SINGLE_CHANNEL pngs");
                    stackmode = 5;
                }
                else if(token.equals("MULTICHANNEL_PNG"))
                {
                    System.out.println("pngmode: MULTI_CHANNEL pngs");
                    stackmode = 6;
                }
            }
        }
    }
    public static void main(String[] args) throws Exception
    {   
        System.out.println("=============================================");
        System.out.println("BIOFORMATSCONVERTER");
        System.out.println("author: Jerome Avondo.");
        System.out.println("");
        System.out.println("=============================================");

        //System.out.println("Reading settings.txt file");
        //Start by reading the user setting in the settings.txt file.
        readSettings("settings.txt");
        if(savemode==0 || stackmode==0)
        {
            System.out.println("ERROR: Reading the Setting.txt file");
            return;
        }
        System.out.println("=============================================");
        System.out.println("");
        
        //Now get all the file in the IN/ directory that we want to proccess.
        String inputdir = "IN/";
        File dir = new File(inputdir);
        String[] children = dir.list();
        if (children == null)
        {
            System.out.println("ERROR: Could not find the IN/ directory!");
            return;
        }
        else
        {
            for (int i=0; i<children.length; i++)
            {
                //progress(i, children.length);
                // Get filename of file or directory
                String current_file = inputdir+children[i];
                //System.out.println(current_file);

                //create a subfolder with the image name
                String outputsubdir = children[i];
                outputsubdir = outputsubdir.replace(".", "_");
                outputsubdir = outputsubdir + "/";

                boolean dircreate = (new File("OUT/"+outputsubdir)).mkdir();
                if(dircreate)
                {
                    //System.out.println("Directory: created");
                }

                boolean fileexists = (new File(current_file)).exists();
                boolean isdirectory = (new File(current_file)).isDirectory();

                if(fileexists==true && isdirectory==false)
                {
                    System.out.println("=============================================");
                    System.out.println("CURRENT FILE: " + current_file);
                    System.out.println("File : " + (i+1) + " of " + children.length);
                    System.out.println("=============================================");

                    if(savemode==1) //TIFF
                    {
                        if(stackmode==1)
                        {
                            System.out.println("SAVEMODE: SINGLE_TIFFS");
                            saveImageToOMETIFF(current_file, "OUT/"+outputsubdir);
                        } //SINGLE
                        else if(stackmode==2)
                        {
                            System.out.println("SAVEMODE: Z_STACKS");
                            saveImageToOMETIFF_Zstack(current_file, "OUT/"+outputsubdir);
                        } //Z_STACKS
                        else if(stackmode==3)
                        {
                            System.out.println("SAVEMODE: ZC_STACKS");
                            saveImageToOMETIFF_ZCstack(current_file, "OUT/"+outputsubdir);
                        } //ZC_STACKS
                        else if(stackmode==4)
                        {
                            System.out.println("SAVEMODE: ZCT_STACKS");
                            saveImageToOMETIFF_ZCTstack(current_file, "OUT/"+outputsubdir);
                        } //ZCT_STACKS
                    }
                    else if(savemode==2) //PNG
                    {
                        if(stackmode==5)
                        {
                            System.out.println("SAVEMODE: SINGLE_PNG");
                            saveImageToPNG_singlechannel(current_file, "OUT/"+outputsubdir);
                       } //ZCT_STACKS
                       else if(stackmode==6)
                       {
                            System.out.println("SAVEMODE: MULTICHANNEL_PNG");
                            saveImageToPNG_multichannel(current_file, "OUT/"+outputsubdir);
                       } //ZCT_STACKS

                    }
                }
                else
                {
                    System.out.println("ERROR: Could not find " + current_file +" !");
                    return;
                }
            }
        }
        System.out.println("=============================================");
        System.out.println("Finished...");

    }
}

