Beispiel #1
0
        public Correlator(MosaicInfo mosaicInfo, TiledImageView correlationDisplayViewer)
            : this(correlationDisplayViewer)
        {
            this.mosaicInfo = mosaicInfo;

            CreateCorrelationTileList();
        }
Beispiel #2
0
        public Correlator(MosaicInfo mosaicInfo, TiledImageView correlationDisplayViewer)
            : this(correlationDisplayViewer)
        {
            this.mosaicInfo = mosaicInfo;

            CreateCorrelationTileList();
        }
Beispiel #3
0
        public override void Reset(MosaicInfo info)
        {
            this.MosaicInfo = info;

            double pixels = 1.0;

            if (this.MosaicInfo.HasConstantOverlap)
            {
                pixels = (Math.Min(this.MosaicInfo.OverLapPercentageX, this.MosaicInfo.OverLapPercentageY) / 100.0)
                         * this.MosaicInfo.Items[0].Width;
            }
            else
            {
                // There is no constant overlap
                // Lets default to 500 pixels or the image width which ever the smaller.
                pixels = (Math.Min(500, Tile.SmallestTileWidth(this.MosaicInfo.Items)));
                pixels = (Math.Min(pixels, Tile.SmallestTileHeight(this.MosaicInfo.Items)));
            }

            this.OverlapInMicrons = (int)(pixels * this.MosaicInfo.OriginalMicronsPerPixel);

            // By default set strip size to 20% of overlap
            this.StripSize = (int)(this.OverlapInMicrons * 0.2);

            // By default set the search size to 40 % of the overlap
            this.SearchSize = (int)(this.OverlapInMicrons * 0.4);

            this.searchAllEdgesCheckBox.Checked = true;

            this.preFilter.SelectedIndex = 0;
        }
Beispiel #4
0
        internal void LoadMosaicInfo(MosaicInfo mosaicInfo)
        {
            this.mosaicInfo = mosaicInfo;

            Tile tile = mosaicInfo.Items[0];

            this.DestroyIntermediateBitmap();

            this.Clear();
            this.CalculateVisibleTiles();
        }
Beispiel #5
0
        public KernalBasedOverlapCorrelator(MosaicInfo mosaicInfo, TiledImageView correlationDisplayViewer)
            : base(mosaicInfo, correlationDisplayViewer)
        {
            this.knownOverlapCorrelatorOptionPanel = new KernelBasedOverlapCorrelatorOptionPanel(this);

            this.CorrelationDisplayViewer.TileImageViewMouseDownHandler +=
                new TileImageViewMouseDelegate <TiledImageView, TiledImageViewMouseEventArgs>(OnCorrelationTileImageViewMouseDownHandler);

            this.CorrelationDisplayViewer.TileImageViewMouseMoveHandler +=
                new TileImageViewMouseDelegate <TiledImageView, TiledImageViewMouseEventArgs>(OnCorrelationTileImageViewMouseMoveHandler);

            this.CorrelationDisplayViewer.Paint += new PaintEventHandler(OnCorrelationTileImageViewPaint);
        }
        public KernalBasedOverlapCorrelator(MosaicInfo mosaicInfo, TiledImageView correlationDisplayViewer)
            : base(mosaicInfo, correlationDisplayViewer)
        {
            this.knownOverlapCorrelatorOptionPanel = new KernelBasedOverlapCorrelatorOptionPanel(this);

            this.CorrelationDisplayViewer.TileImageViewMouseDownHandler +=
                new TileImageViewMouseDelegate<TiledImageView, TiledImageViewMouseEventArgs>(OnCorrelationTileImageViewMouseDownHandler);

            this.CorrelationDisplayViewer.TileImageViewMouseMoveHandler +=
                new TileImageViewMouseDelegate<TiledImageView, TiledImageViewMouseEventArgs>(OnCorrelationTileImageViewMouseMoveHandler);

            this.CorrelationDisplayViewer.Paint += new PaintEventHandler(OnCorrelationTileImageViewPaint);
        }
Beispiel #7
0
        public SaveDialog(MosaicInfo mosaicInfo, RoiTool tool)
        {
            InitializeComponent();

            this.tool = tool;

            this.imageRegion = Rectangle.Empty;

            if (tool.Active == true)
            {
                this.imageRegion = tool.TransformedRegionOfInterest;
            }

            tool.RoiToolDrawnHandler       += new RoiToolHandler <RoiTool, RoiToolEventArgs>(OnRoiToolDrawnHandler);
            tool.PluginActiveStatusChanged +=
                new MosaicPluginEventHandler <MosaicPlugin, EventArgs>(OnRoiPluginActiveStatusChanged);

            this.widthNumeric.Minimum  = 100;
            this.widthNumeric.Maximum  = 1000000;
            this.heightNumeric.Minimum = 100;
            this.heightNumeric.Maximum = 1000000;

            if (MosaicWindow.MosaicInfo.TotalWidth > SaveDialog.MaxPossibleWidth)
            {
                this.MaxWidth = MaxPossibleWidth;
            }
            else
            {
                this.MaxWidth = MosaicWindow.MosaicInfo.TotalWidth;
            }

            if (MosaicWindow.MosaicInfo.TotalHeight > SaveDialog.MaxPossibleWidth)
            {
                this.MaxHeight = MaxPossibleHeight;
            }
            else
            {
                this.MaxHeight = MosaicWindow.MosaicInfo.TotalHeight;
            }

            CalculateAspectRatio();

            this.filePathCombo.Items.Add(MosaicWindow.MosaicInfo.DirectoryPath);
            this.filePathCombo.Text = MosaicWindow.MosaicInfo.DirectoryPath;

            this.OnExportSizeNumericValidating(this.widthNumeric, new CancelEventArgs());

            this.widthNumeric.ValueChanged  += new EventHandler(this.OnNumericValueChanged);
            this.heightNumeric.ValueChanged += new EventHandler(this.OnNumericValueChanged);
        }
Beispiel #8
0
        public SaveDialog(MosaicInfo mosaicInfo, RoiTool tool)
        {
            InitializeComponent();

            this.tool = tool;

            this.imageRegion = Rectangle.Empty;

            if (tool.Active == true)
                this.imageRegion = tool.TransformedRegionOfInterest;

            tool.RoiToolDrawnHandler += new RoiToolHandler<RoiTool, RoiToolEventArgs>(OnRoiToolDrawnHandler);
            tool.PluginActiveStatusChanged +=
                new MosaicPluginEventHandler<MosaicPlugin, EventArgs>(OnRoiPluginActiveStatusChanged);

            this.widthNumeric.Minimum = 100;
            this.widthNumeric.Maximum = 1000000;
            this.heightNumeric.Minimum = 100;
            this.heightNumeric.Maximum = 1000000;

            if (MosaicWindow.MosaicInfo.TotalWidth > SaveDialog.MaxPossibleWidth)
                this.MaxWidth = MaxPossibleWidth;
            else
                this.MaxWidth = MosaicWindow.MosaicInfo.TotalWidth;

            if (MosaicWindow.MosaicInfo.TotalHeight > SaveDialog.MaxPossibleWidth)
                this.MaxHeight = MaxPossibleHeight;
            else
                this.MaxHeight = MosaicWindow.MosaicInfo.TotalHeight;

            CalculateAspectRatio();

            this.filePathCombo.Items.Add(MosaicWindow.MosaicInfo.DirectoryPath);
            this.filePathCombo.Text = MosaicWindow.MosaicInfo.DirectoryPath;

            this.OnExportSizeNumericValidating(this.widthNumeric, new CancelEventArgs());

            this.widthNumeric.ValueChanged += new EventHandler(this.OnNumericValueChanged);
            this.heightNumeric.ValueChanged += new EventHandler(this.OnNumericValueChanged);
        }
        public void Initialise(MosaicInfo info, Rectangle virtualArea, Size imageSize, bool forceGreyscale)
        {
            this.info           = info;
            this.virtualArea    = virtualArea;
            this.forceGreyscale = forceGreyscale;

            float aspectRatio = (float)(virtualArea.Width) / virtualArea.Height;

            if (imageSize.Width < imageSize.Height)
            {
                imageSize.Width = (int)(imageSize.Height * aspectRatio + 0.5);
            }
            else
            {
                imageSize.Height = (int)(imageSize.Width / aspectRatio + 0.5);
            }

            if (this.info != null)
            {
                xScaleFactor = (float)imageSize.Width / virtualArea.Width;
                yScaleFactor = (float)imageSize.Height / virtualArea.Height;

                // Set the view zoom factor so the large background image is fit to window
                // by default.
                float factor = Math.Min((float)this.Width / imageSize.Width,
                                        (float)this.Height / imageSize.Height);
                this.Zoom = factor;
            }

            if (this.forceGreyscale || info.IsGreyScale)
            {
                this.image = new FreeImageAlgorithmsBitmap(imageSize.Width, imageSize.Height, 8);
            }
            else
            {
                this.image = new FreeImageAlgorithmsBitmap(imageSize.Width, imageSize.Height, 24);
            }
        }
 public TiledImageView(MosaicInfo info, Rectangle virtualArea, Size imageSize)
 {
     Initialise(info, virtualArea, imageSize, false);
 }
 public TiledImageView(MosaicInfo info, Rectangle virtualArea, Size imageSize, bool forceGreyscale)
 {
     Initialise(info, virtualArea, imageSize, forceGreyscale);
 }
Beispiel #12
0
        internal void LoadMosaicInfo(MosaicInfo mosaicInfo)
        {
            this.mosaicInfo = mosaicInfo;

            Tile tile = mosaicInfo.Items[0];

            this.DestroyIntermediateBitmap();

            this.Clear();
            this.CalculateVisibleTiles();
        }
 public virtual void Reset(MosaicInfo info)
 {
 }
Beispiel #14
0
        internal static void SaveMosaicHeader(MosaicInfo info, StreamWriter sw)
        {
            sw.Write("1.6\u0000");
            sw.Write(info.WidthInTiles + "\u0000");
            sw.Write(info.HeightInTiles + "\u0000");
            sw.Write(info.TotalWidth + "\u0000");
            sw.Write(info.TotalHeight + "\u0000");
            sw.Write(info.ColorDepth + "\u0000");
            sw.Write(info.OriginalPixelsPerMicron + "\u0000");
            sw.Write(info.OverLapPercentageX + "\u0000");
            sw.Write(info.OverLapPercentageY + "\u0000");
            sw.Write("0.0\u0000");  // dummy - was used for the overlap
            sw.Write(info.TotalMinIntensity + "\u0000");
            sw.Write(info.TotalMaxIntensity + "\u0000");
            sw.Write((int)info.FreeImageType + "\u0000");
            sw.Write(info.Items.Count + "\u0000");
            sw.Write(info.Items[0].Thumbnail.Width + "\u0000");
            sw.Write(info.Items[0].Thumbnail.Height + "\u0000");

            sw.Write(info.IsCorrelated + "\u0000\r\n");
            sw.Write(info.Prefix + "\u0000\r\n");

            foreach (Tile tile in info.Items)
            {
             /*               string filename, filename2, filename3;

                filename = tile.getFileName(0); // should always have one

                try { filename2 = tile.getFileName(1); }
                catch { filename2 = ""; }
                try { filename3 = tile.getFileName(2); }
                catch { filename3 = ""; }
               */

                sw.WriteLine(String.Format(
                    "{0}\u0000{1}\u0000{2}\u0000{3}\u0000{4}\u0000{5}\u0000{6}\u0000{7}\u0000{8}\u0000{9}"
                    + "\u0000{10}\u0000{11}\u0000{12}\u0000{13}\u0000{14}",
                    tile.getFileName(0).ToString(),
                    tile.getFileName(1).ToString(),
                    tile.getFileName(2).ToString(),
                    tile.OriginalPosition.X,
                    tile.OriginalPosition.Y,
                    tile.Width,
                    tile.Height,
                    tile.ColorDepth,
                    tile.MinIntensity,
                    tile.MaxIntensity,
                    (int)tile.FreeImageType,
                    tile.IsDummy,
                    tile.AdjustedPosition.X,
                    tile.AdjustedPosition.Y,
                    tile.IsAdjusted
                    ));
            }

            // composite image stuff
            sw.Write(Tile.IsCompositeRGB + "\u0000");
            sw.Write(Tile.nCompositeImages + "\u0000");
            sw.Write((int)Tile.channel[0] + "\u0000");
            sw.Write((int)Tile.channel[1] + "\u0000");
            sw.Write((int)Tile.channel[2] + "\u0000");
            sw.Write(Tile.scaleMin[0] + "\u0000");
            sw.Write(Tile.scaleMin[1] + "\u0000");
            sw.Write(Tile.scaleMin[2] + "\u0000");
            sw.Write(Tile.scaleMax[0] + "\u0000");
            sw.Write(Tile.scaleMax[1] + "\u0000");
            sw.Write(Tile.scaleMax[2] + "\u0000");
            sw.Write(Tile.channelShift[0].X + "\u0000");
            sw.Write(Tile.channelShift[0].Y + "\u0000");
            sw.Write(Tile.channelShift[1].X + "\u0000");
            sw.Write(Tile.channelShift[1].Y + "\u0000");
            sw.Write(Tile.channelShift[2].X + "\u0000");
            sw.Write(Tile.channelShift[2].Y + "\u0000");
            sw.Write(Tile.channelPrefix[0] + "\u0000\r\n");
            sw.Write(Tile.channelPrefix[1] + "\u0000\r\n");
            sw.Write(Tile.channelPrefix[2] + "\u0000\r\n");

            sw.Flush();
        }
 public virtual void Reset(MosaicInfo info)
 {
 }
Beispiel #16
0
 public TiledImageView(MosaicInfo info, Rectangle virtualArea, Size imageSize)
 {
     Initialise(info, virtualArea, imageSize, false);
 }
Beispiel #17
0
 public TiledImageView(MosaicInfo info, Rectangle virtualArea, Size imageSize, bool forceGreyscale)
 {
     Initialise(info, virtualArea, imageSize, forceGreyscale);
 }
Beispiel #18
0
        public void Initialise(MosaicInfo info, Rectangle virtualArea, Size imageSize, bool forceGreyscale)
        {
            this.info = info;
            this.virtualArea = virtualArea;
            this.forceGreyscale = forceGreyscale;

            float aspectRatio = (float)(virtualArea.Width) / virtualArea.Height;

            if (imageSize.Width < imageSize.Height)
            {
                imageSize.Width = (int)(imageSize.Height * aspectRatio + 0.5);
            }
            else
            {
                imageSize.Height = (int)(imageSize.Width / aspectRatio + 0.5);
            }

            if (this.info != null)
            {
                xScaleFactor = (float)imageSize.Width / virtualArea.Width;
                yScaleFactor = (float)imageSize.Height / virtualArea.Height;

                // Set the view zoom factor so the large background image is fit to window
                // by default.
                float factor = Math.Min((float)this.Width / imageSize.Width,
                                        (float)this.Height / imageSize.Height);
                this.Zoom = factor;
            }

            if (this.forceGreyscale || info.IsGreyScale)
                this.image = new FreeImageAlgorithmsBitmap(imageSize.Width, imageSize.Height, 8);
            else
                this.image = new FreeImageAlgorithmsBitmap(imageSize.Width, imageSize.Height, 24);
        }
Beispiel #19
0
        public void Open(string[] originalFilePaths)
        {
            this.originalFilePaths = originalFilePaths;
            string[] cachefilePaths = new string[1];

            MosaicPlugin.AllPlugins["Linear Scale"].Enabled = false;
            MosaicPlugin.AllPlugins["RGB Balance"].Enabled = false;

            TileReader[] tileReaders = new TileReader[6];

            tileReaders[0] = new MosaicFileReader(originalFilePaths, this);
            tileReaders[1] = new Version2SequenceFileReader(originalFilePaths, this);
            tileReaders[2] = new SequenceFileReader(originalFilePaths, this);
            tileReaders[3] = new RosMosaicSequenceFileReader(originalFilePaths, this);
            tileReaders[4] = new ImageCollectionFileReader(originalFilePaths, this);
            tileReaders[5] = new MultiSequenceFileReader(originalFilePaths, this);

            foreach (TileReader t in tileReaders)
            {
                if (t.CanRead())
                {
                    originalTileReader = tileReader = t;

                    break;
                }
            }

            if(tileReader == null) {
                MessageBox.Show("Unknown file type");
                return;
            }

            // Check if there is cache availiable for this file
            if (tileReader.HasCache())
            {
                cachefilePaths[0] = tileReader.GetCacheFilePath();

                if (tileReader.GetType() != typeof(MosaicFileReader))   // create a new reader to read this cache, if we opened a mos file, we already have the reader
                    tileReader = new MosaicFileReader(cachefilePaths, this);
            }

            this.menuStrip.Enabled = false;
            this.toolStrip.Enabled = false;

            ToolStripProgressBar progressbar = (ToolStripProgressBar)this.feedbackStatusStrip.Items[1];

            openThreadController = new ThreadController(this);
            openThreadController.SetThreadCompletedCallback(OpenFileThreadCompleted);
            openThreadController.SetThreadProgressCallback(OpenFileProgressIndicator);
            tileReader.SetThreadController(openThreadController);

            progressbar.Value = 0;
            this.statusStrip.Refresh();

            try
            {
                tileReader.ReadHeader();
            }
            catch (MosaicException e)
            {
                // The cache file failed to be read.
                // Probably as the format has changed. Here we delete the cache file and recall the open function

                if (tileReader.GetType() == typeof(MosaicFileReader))
                {
                    if (originalTileReader.GetType() != typeof(MosaicFileReader))
                    {
                        File.Delete(cachefilePaths[0]);
                        this.Open(originalFilePaths);
                    }
                    else
                    {
                        // The user has tried to open the mos (cache) file directly
                        // We don't know what other files to fall back too so we just error and return.
                        // File.Delete(cachefilePaths[0]);   // DO NOT DELETE THE FILE THEY JUST TRIED TO OPEN!
                        MessageBox.Show("Unable to load file", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                        return;
                    }
                }
                else
                {
                    MessageBox.Show(e.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    return;
                }
            }
            catch (Exception e)
            {
                MessageBox.Show("Failed to read header information correctly. " + e.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }
            finally
            {
                this.menuStrip.Enabled = true;
                this.toolStrip.Enabled = true;
            }

            MosaicWindow.MosaicInfo = new MosaicInfo(tileReader);

            this.tileOverView.CreateOverview();

            this.tileOverView.Location = new Point(25, this.TileView.Bottom - this.tileOverView.Height - 25);

            this.tileOverView.Show();

            // TileLoadInfo should now be ready as we have read the header.
            this.BlendingEnabled = true;
            this.CorrelationEnabled = true;

            // Threaded Operation
            tileReader.CreateThumbnails();
        }
Beispiel #20
0
 public MosaicWindowEventArgs(MosaicInfo info)
 {
     this.info = info;
 }
        public override void Reset(MosaicInfo info)
        {
            this.MosaicInfo = info;

            double pixels = 1.0;

            if (this.MosaicInfo.HasConstantOverlap)
            {
                pixels = (Math.Min(this.MosaicInfo.OverLapPercentageX, this.MosaicInfo.OverLapPercentageY) / 100.0)
                     * this.MosaicInfo.Items[0].Width;
            }
            else
            {
                // There is no constant overlap
                // Lets default to 500 pixels or the image width which ever the smaller.
                pixels = (Math.Min(500, Tile.SmallestTileWidth(this.MosaicInfo.Items)));
                pixels = (Math.Min(pixels, Tile.SmallestTileHeight(this.MosaicInfo.Items)));
            }

            this.OverlapInMicrons = (int)(pixels * this.MosaicInfo.OriginalMicronsPerPixel);

            // By default set strip size to 20% of overlap
            this.StripSize = (int)(this.OverlapInMicrons * 0.2);

            // By default set the search size to 40 % of the overlap
            this.SearchSize = (int)(this.OverlapInMicrons * 0.4);

            this.searchAllEdgesCheckBox.Checked = true;

            this.preFilter.SelectedIndex = 0;
        }
Beispiel #22
0
        public void Open(string[] originalFilePaths)
        {
            this.originalFilePaths = originalFilePaths;
            string[] cachefilePaths = new string[1];

            MosaicPlugin.AllPlugins["Linear Scale"].Enabled = false;
            MosaicPlugin.AllPlugins["RGB Balance"].Enabled  = false;

            TileReader[] tileReaders = new TileReader[6];

            tileReaders[0] = new MosaicFileReader(originalFilePaths, this);
            tileReaders[1] = new Version2SequenceFileReader(originalFilePaths, this);
            tileReaders[2] = new SequenceFileReader(originalFilePaths, this);
            tileReaders[3] = new RosMosaicSequenceFileReader(originalFilePaths, this);
            tileReaders[4] = new ImageCollectionFileReader(originalFilePaths, this);
            tileReaders[5] = new MultiSequenceFileReader(originalFilePaths, this);

            foreach (TileReader t in tileReaders)
            {
                if (t.CanRead())
                {
                    originalTileReader = tileReader = t;

                    break;
                }
            }

            if (tileReader == null)
            {
                MessageBox.Show("Unknown file type");
                return;
            }

            // Check if there is cache availiable for this file
            if (tileReader.HasCache())
            {
                cachefilePaths[0] = tileReader.GetCacheFilePath();

                if (tileReader.GetType() != typeof(MosaicFileReader))   // create a new reader to read this cache, if we opened a mos file, we already have the reader
                {
                    tileReader = new MosaicFileReader(cachefilePaths, this);
                }
            }

            this.menuStrip.Enabled = false;
            this.toolStrip.Enabled = false;

            ToolStripProgressBar progressbar = (ToolStripProgressBar)this.feedbackStatusStrip.Items[1];

            openThreadController = new ThreadController(this);
            openThreadController.SetThreadCompletedCallback(OpenFileThreadCompleted);
            openThreadController.SetThreadProgressCallback(OpenFileProgressIndicator);
            tileReader.SetThreadController(openThreadController);

            progressbar.Value = 0;
            this.statusStrip.Refresh();

            try
            {
                tileReader.ReadHeader();
            }
            catch (MosaicException e)
            {
                // The cache file failed to be read.
                // Probably as the format has changed. Here we delete the cache file and recall the open function

                if (tileReader.GetType() == typeof(MosaicFileReader))
                {
                    if (originalTileReader.GetType() != typeof(MosaicFileReader))
                    {
                        File.Delete(cachefilePaths[0]);
                        this.Open(originalFilePaths);
                    }
                    else
                    {
                        // The user has tried to open the mos (cache) file directly
                        // We don't know what other files to fall back too so we just error and return.
                        // File.Delete(cachefilePaths[0]);   // DO NOT DELETE THE FILE THEY JUST TRIED TO OPEN!
                        MessageBox.Show("Unable to load file", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                        return;
                    }
                }
                else
                {
                    MessageBox.Show(e.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    return;
                }
            }
            catch (Exception e)
            {
                MessageBox.Show("Failed to read header information correctly. " + e.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }
            finally
            {
                this.menuStrip.Enabled = true;
                this.toolStrip.Enabled = true;
            }

            MosaicWindow.MosaicInfo = new MosaicInfo(tileReader);

            this.tileOverView.CreateOverview();

            this.tileOverView.Location = new Point(25, this.TileView.Bottom - this.tileOverView.Height - 25);

            this.tileOverView.Show();

            // TileLoadInfo should now be ready as we have read the header.
            this.BlendingEnabled    = true;
            this.CorrelationEnabled = true;

            // Threaded Operation
            tileReader.CreateThumbnails();
        }
Beispiel #23
0
 public MosaicWindowEventArgs(MosaicInfo info)
 {
     this.info = info;
 }
Beispiel #24
0
        internal static void SaveMosaicHeader(MosaicInfo info, StreamWriter sw)
        {
            sw.Write("1.6\u0000");
            sw.Write(info.WidthInTiles + "\u0000");
            sw.Write(info.HeightInTiles + "\u0000");
            sw.Write(info.TotalWidth + "\u0000");
            sw.Write(info.TotalHeight + "\u0000");
            sw.Write(info.ColorDepth + "\u0000");
            sw.Write(info.OriginalPixelsPerMicron + "\u0000");
            sw.Write(info.OverLapPercentageX + "\u0000");
            sw.Write(info.OverLapPercentageY + "\u0000");
            sw.Write("0.0\u0000");  // dummy - was used for the overlap
            sw.Write(info.TotalMinIntensity + "\u0000");
            sw.Write(info.TotalMaxIntensity + "\u0000");
            sw.Write((int)info.FreeImageType + "\u0000");
            sw.Write(info.Items.Count + "\u0000");
            sw.Write(info.Items[0].Thumbnail.Width + "\u0000");
            sw.Write(info.Items[0].Thumbnail.Height + "\u0000");

            sw.Write(info.IsCorrelated + "\u0000\r\n");
            sw.Write(info.Prefix + "\u0000\r\n");

            foreach (Tile tile in info.Items)
            {
                /*               string filename, filename2, filename3;
                 *
                 *             filename = tile.getFileName(0); // should always have one
                 *
                 *             try { filename2 = tile.getFileName(1); }
                 *             catch { filename2 = ""; }
                 *             try { filename3 = tile.getFileName(2); }
                 *             catch { filename3 = ""; }
                 */

                sw.WriteLine(String.Format(
                                 "{0}\u0000{1}\u0000{2}\u0000{3}\u0000{4}\u0000{5}\u0000{6}\u0000{7}\u0000{8}\u0000{9}"
                                 + "\u0000{10}\u0000{11}\u0000{12}\u0000{13}\u0000{14}",
                                 tile.getFileName(0).ToString(),
                                 tile.getFileName(1).ToString(),
                                 tile.getFileName(2).ToString(),
                                 tile.OriginalPosition.X,
                                 tile.OriginalPosition.Y,
                                 tile.Width,
                                 tile.Height,
                                 tile.ColorDepth,
                                 tile.MinIntensity,
                                 tile.MaxIntensity,
                                 (int)tile.FreeImageType,
                                 tile.IsDummy,
                                 tile.AdjustedPosition.X,
                                 tile.AdjustedPosition.Y,
                                 tile.IsAdjusted
                                 ));
            }

            // composite image stuff
            sw.Write(Tile.IsCompositeRGB + "\u0000");
            sw.Write(Tile.nCompositeImages + "\u0000");
            sw.Write((int)Tile.channel[0] + "\u0000");
            sw.Write((int)Tile.channel[1] + "\u0000");
            sw.Write((int)Tile.channel[2] + "\u0000");
            sw.Write(Tile.scaleMin[0] + "\u0000");
            sw.Write(Tile.scaleMin[1] + "\u0000");
            sw.Write(Tile.scaleMin[2] + "\u0000");
            sw.Write(Tile.scaleMax[0] + "\u0000");
            sw.Write(Tile.scaleMax[1] + "\u0000");
            sw.Write(Tile.scaleMax[2] + "\u0000");
            sw.Write(Tile.channelShift[0].X + "\u0000");
            sw.Write(Tile.channelShift[0].Y + "\u0000");
            sw.Write(Tile.channelShift[1].X + "\u0000");
            sw.Write(Tile.channelShift[1].Y + "\u0000");
            sw.Write(Tile.channelShift[2].X + "\u0000");
            sw.Write(Tile.channelShift[2].Y + "\u0000\r\n");
            sw.Write(Tile.channelPrefix[0] + "\u0000\r\n");
            sw.Write(Tile.channelPrefix[1] + "\u0000\r\n");
            sw.Write(Tile.channelPrefix[2] + "\u0000\r\n");

            sw.Flush();
        }