Show a multipage tiff file (by libtiff.net) with ImageAnnotation

May 8, 2014 at 10:53 AM
Edited May 8, 2014 at 1:17 PM
Hi,
I have a multipage tiff video (8 bit grayscale), I would like to show the frames in OxyPlot WPF plot control.

I am using libtfff.net to read the multipage tiff, all data are stored in a byte[] buf array; now the problem is that I do not know how to use this array with ImageAnnotation, sorry for the noob question, is there a way?

This is my code
            // open a tiff
            Tiff tiff = Tiff.Open("merged8bit.tif", "r");

            // read tiff image
            FieldValue[] value = tiff.GetField(TiffTag.IMAGELENGTH);
            int imageLength = value[0].ToInt();

            Bitmap bitmap = new Bitmap(tiff.ScanlineSize(), imageLength, System.Drawing.Imaging.PixelFormat.Format32bppArgb);

            byte[] buf = new byte[tiff.ScanlineSize()];

            for (int row = 0; row < imageLength; row++)
            {
                tiff.ReadScanline(buf, row);
                for (int col = 0; col < tiff.ScanlineSize(); col++)
                {
                    bitmap.SetPixel(col, row, System.Drawing.Color.FromArgb(0, buf[col], buf[col], buf[col]));
                }
            }

            // create a model
            PlotModel model = new PlotModel();
            Plot.Model = model;

            model.Title = "TIFF";

            LinearAxis 
                axisX = new LinearAxis(),
                axisY = new LinearAxis();
            axisX.Position = AxisPosition.Bottom;

            model.Axes.Add(axisX);
            model.Axes.Add(axisY);

            ImageAnnotation image = new ImageAnnotation();
            image.HorizontalAlignment = OxyPlot.HorizontalAlignment.Left;
            image.VerticalAlignment = OxyPlot.VerticalAlignment.Top;

            MemoryStream stream = new MemoryStream();
            bitmap.Save(stream, System.Drawing.Imaging.ImageFormat.Bmp);

            // Exception: invalid format
            image.ImageSource = new OxyImage(stream);

            model.Annotations.Add(image);

            stream.Close();
            tiff.Close();
Thanks a lot for any help :)
May 8, 2014 at 2:38 PM
Edited May 8, 2014 at 5:32 PM
I have found a solution: HeatMapSeries... but the rendering speed is bad and I have a problem in visualization (I need to 'transpose' the final plot). I hope there is another solution.
            // open a tiff
            Tiff tiff = Tiff.Open("merged8bit.tif", "r");

            // read tiff image
            FieldValue[] value = tiff.GetField(TiffTag.IMAGELENGTH);
            int imageLength = value[0].ToInt();

            // create a model
            PlotModel model = new PlotModel();

            LinearColorAxis colorAxis = new LinearColorAxis();
            colorAxis.Position = AxisPosition.Right;
            colorAxis.LowColor = OxyColors.White;
            colorAxis.HighColor = OxyColors.White;

            var palette = OxyPalette.Interpolate(255, OxyColors.Black, OxyColors.White);
            colorAxis.Palette = palette;

            model.Axes.Add(colorAxis);

            var heatMapSeries1 = new HeatMapSeries();
            heatMapSeries1.X0 = 0;
            heatMapSeries1.Y0 = tiff.ScanlineSize();
            heatMapSeries1.X1 = imageLength;
            heatMapSeries1.Y1 = 0;
            heatMapSeries1.Interpolate = false;
            heatMapSeries1.Data = new Double[imageLength, tiff.ScanlineSize()];

            byte[] buf = new byte[tiff.ScanlineSize()];

            for (int row = 0; row < imageLength; row++)
            {
                tiff.ReadScanline(buf, row);
                Parallel.For(0, tiff.ScanlineSize(), col =>
                {
                    heatMapSeries1.Data[row, col] = buf[col];
                });
            }

            model.Title = "TIFF";

            LinearAxis 
                axisX = new LinearAxis(),
                axisY = new LinearAxis();
            axisX.Position = AxisPosition.Bottom;

            model.Axes.Add(axisX);
            model.Axes.Add(axisY);

            model.Series.Add(heatMapSeries1);

            model.PlotType = PlotType.Cartesian;

            Plot.Model = model;

            tiff.Close();
Coordinator
May 10, 2014 at 9:28 PM
I think it is best to use the OxyImage solution. Can you try saving the image data to PNG instead? BMP may not be fully implemented.
And make sure the MemoryStream is positioned at the start when you pass the stream to the constructor. Consider using the OxyImage(byte[]) constructor instead.
May 19, 2014 at 10:50 PM
Edited May 21, 2014 at 3:27 PM
Hi,
sorry for late reply, it is working :) the problem was about seek in MemoryStream (the fix is stream.Seek(0, SeekOrigin.Begin)) like you mentioned.

P.S.
Sometimes an exception occours at image.ImageSource = new OxyImage(stream);Is it a bug?

The exception is:
System.ArgumentOutOfRangeExcpetion
"Index was out of range. Must be non-negative and less than the size of the collection.\r\nParameter name: startIndex"}