MakeBitmap from the Diagram

Hi,
We use Northwoods.GoWPF version 1.3.5.4 to create TreeLayout Diagram which may contains more than 1000 nodes. After exporting this diagram to the png format file by using suggestion from the forum

Panel.MakeBitmap(new System.Windows.Size(width, height), dpi, BitmapViewPos, s); we get whole diagram but part of the text or labels disappeared.

Please see attached examples:
First image before exporting:

Second image after exporting:

Please pay attention the to right side of the diagram . All text disappeared.

We did many iterations and investigations and payed attention that it’s happens every time after exceeding specific number of the nodes. It’s happens not just in this use case but in many others cases with large amount of the nodes.When we use diagram with less than 1000 nodes everything work properly without problem.

Any suggestions ???

How large (wide) is the bitmap when you see this problem? Might the problem be due to the width (or height) of the bitmap, not the actual number of nodes?

I dont think that problem with width because after exporting i can see whole diagram with all nodes only without labels.If you wish i can post all diagram view ???

thank you for the quick response

Actually, I think it does matter how wide the bitmap is, because there may be limitations (beyond our control) in how WPF renders text when drawing to a bitmap.

For example, if you cut the bitmap Size width and height in half and cut the scale in half, does the text get drawn OK?

Hi,

Here is actual size of my diagram

Panel.MakeBitmap(new System.Windows.Size(width, height), dpi, BitmapViewPos, s);

where width = 26567 and height = 1498.75

Thx

We need some solution in order to resolve this issue , because now we are running production. We have support subscription so if your need some official ticket from our company please let me know.

Thx

Have you had the chance to try what I suggested? For a diagram whose bitmap exhibits the missing text, try producing a smaller bitmap at a proportionally smaller scale.

Hi,
I did it and got result with some observation :

1.First of all you are right problem with size of the diagram.

2.After reducing scale , width and height accordingly i can see text ,but very low quality.

3.Now i cannot see another part of diagram text (so problem just shifted :) to the next level of the diagram)


In conclusion first of all thank you for the quick response.


Now we need some solution of this problem/bug . We can’t reduce scale of the diagram because quality very important issue for us and our customers. Our customer need to see whole diagram in order to print it by Plotter.


Best regards

What do you mean by the next level of the diagram?

So there are no error or warning messages?

I would draw limited size bitmaps as separate files and then stitch them back together when needed.

Hi,
there are no error or warning.
Next level of diagram mean that when scale was 1 cutting text started from the node 200 for example and now after reducing scale cutting text shifted to the node 300 for example.

According to the limited size of the bitmap: i don’t know exactly when diagram cut text , because i have another cases of cutting.

I opened GoXam documentation and did’t find some notes about limitation size of the diagram , so i think that it’s your bug , because i can see whole diagram after export and only some part of the diagram disappeared without some error or warning message.

Your suggestion about separate export bitmap unacceptable because we need one image.

I would like to open official ticket about this issue . How can i do it ?

Fundamentally, DiagramPanel.MakeBitmap is implemented as:

    Size modsz = new Size(bmpsize.Width/scale, bmpsize.Height/scale);
    Measure(modsz);
    Arrange(new Rect(0, 0, modsz.Width, modsz.Height));
    var bmp = new RenderTargetBitmap((int)Math.Ceiling(bmpsize.Width), (int)Math.Ceiling(bmpsize.Height), dpi, dpi, PixelFormats.Default);
    bmp.Render(this);

There is other preparatory stuff, plus it renders the Diagram.Background, and there is stuff that it has to cleanup afterwards, so this is not the complete code. I’m just posting this to show you what we do.

This is also why I believe you are running into limitations of WPF. You can claim it is our bug, but there isn’t anything that we can do about the things that WPF does not do “correctly”.

There are no official “tickets” – you have already made this problem an “issue”. I’ll try to reproduce the problem later this morning, after I’m awake.

Oh, and my suggestion about producing several images still produces a single image file at the end, after stitching them together. Think of it as implementing tiling.

By the way, is your app running in 32-bit mode or 64-bit mode?

Hi,
Application running in 32-bit mode.
Concerning to WPF limitation i don’t agree with you , because how can you explain fact that after exporting diagram i can see whole diagram (all 1700 nodes) ? I suppose that if there is some WPF rendering problem i will see same behavior during opening diagram inside application . We use zooming , panning , Overview and Zoom to fit functionality without any problem.All elements present on the diagram.

I will think about your suggestion to divide diagram to many parts during exporting.

P.S: In addition i can say that we are really enjoy to use your product and this issue we will resolve Cool

Thx

Hi,
I think that you mean not WPF limitation but C# framework function <h1 =“title” style=“color: rgb0, 0, 0; font-weight: normal; font-size: 2.769em; line-height: 1.167; font-family: ‘Segoe UI’, ‘Lucida Grande’, Verdana, Arial, Helvetica, sans-serif;”>RenderTargetBitmap

Hi,
I did proof of concept by dividing diagram to the parts, compressing to png format, merging to the one image and again compressing to the png format. It’s work.Tongue

Thx

OK, I have tried to reproduce this problem, but I am unable to do so. The PNG image files my app is writing tend to be over 50K wide. Here’s what at the far right side in Photo Viewer:

This is with WPF 4.0 and VS2010 on a Windows 7 x64 system.

And here’s the code:

[code]

<UserControl.Resources>


<go:NodeShape x:Name=“ICON”
go:NodePanel.Figure=“Triangle”
Fill="{Binding Path=Data.Color}"
Stroke=“Black” StrokeThickness=“1”
Width="{Binding Path=Data.Width}"
Height="{Binding Path=Data.Height}"
go:Node.PortId="" />



</UserControl.Resources>

[/code] [code]/* Copyright © Northwoods Software Corporation, 2008-2013. All Rights Reserved. */

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media.Imaging;
using Northwoods.GoXam.Model;

namespace BigTree {
public partial class BigTree : UserControl {
public BigTree() {
InitializeComponent();

  var nodes = new ObservableCollection<NodeData>() { };
  var links = new ObservableCollection<LinkData>() { };

  // create the node data and the link data for the model
  GenerateNodes(nodes);
  GenerateLinks(nodes, links);

  // create the model with the data
  var model = new GraphLinksModel<NodeData, String, String, LinkData>();
  model.LinksSource = links;
  model.NodesSource = nodes;
  myDiagram.Model = model;

  myDiagram.InitialLayoutCompleted += (s, e) => {
    myStatus.Text = myDiagram.Panel.DiagramBounds.ToString();
  };
}

void GenerateImage(Object sender, EventArgs e) {
  Rect bounds = myDiagram.Panel.DiagramBounds;
  double w = bounds.Width;
  double h = bounds.Height;
  double s = 1.0;
  //if (w > 2000) s = 2000/w;
  //if (h > 2000) s = Math.Min(s, 2000/h);
  //w *= s;
  //h *= s;
  myDiagram.Panel.MakeBitmap(new Size(w, h), 96, new Point(bounds.X, bounds.Y), s,
    bmp => {
      PngBitmapEncoder png = new PngBitmapEncoder();
      png.Frames.Add(BitmapFrame.Create(bmp));
      using (System.IO.Stream stream = System.IO.File.Create(@"C:\temp\BigTree.png")) {
        png.Save(stream);
      }
    });
}

// Creates a collection of randomly colored NodeData objects.
private void GenerateNodes(IList<NodeData> nodes) {
  int numNodes = 1999;

  Random rand = new Random();
  for (int i = 0; i < numNodes; i++) {
    var d = new NodeData() {
      Key = i.ToString(),
      Location = new Point(0, 0),
      // Width and Height could be set based on the Category
      // or other information available when creating this node data object
      // assume VirtualTreeLayout will assign the Location
      Color = String.Format("#{0:X}{1:X}{2:X}", 120+rand.Next(100), 120+rand.Next(100), 120+rand.Next(100))
    };
    if (i == 0) d.Location = new Point(0, 0);  // locate root node
    nodes.Add(d);
  }
}

// Takes the collection of nodes and creates a random tree with them by creating LinkData objects
private void GenerateLinks(IList<NodeData> nodes, IList<LinkData> links) {
  int maxLinks = 2;

  var available = new HashSet<NodeData>(nodes);
  Random rand = new Random();
  foreach (NodeData next in nodes) {
    available.Remove(next);
    int children = rand.Next(maxLinks)+1;
    for (int i = 0; i < children; i++) {
      NodeData to = available.FirstOrDefault();
      if (to == null) return;
      available.Remove(to);
      links.Add(new LinkData() { From = next.Key, To = to.Key });
    }
  }
}

}

public class NodeData : GraphLinksModelNodeData {
// assume this won’t change dynamically, so don’t need to call RaisePropertyChanged
public String Color { get; set; }

public double Width {
  get { return _Width; }
  set { if (_Width != value) { double old = _Width; _Width = value; RaisePropertyChanged("Width", old, value); } }
}
private double _Width = 30;

public double Height {
  get { return _Height; }
  set { if (_Height != value) { double old = _Height; _Height = value; RaisePropertyChanged("Height", old, value); } }
}
private double _Height = 30;

}

public class LinkData : GraphLinksModelLinkData<String, String> { }
}[/code]
Could you help me reproduce the problem?

Hi,

Rect b = myDiagram.PrintManager.Diagram.Panel.DiagramBounds;

BitmapSource bmpv = CreatePrintBitmapSource(b, myDiagram, model.NavigatorManager.FTMapNodes);
PngBitmapEncoder png1 = new PngBitmapEncoder();
png1.Frames.Add(BitmapFrame.Create(bmpv));
png1.Save(stream);

private BitmapSource CreatePrintBitmapSource(Rect b, Diagram diag, ObservableCollection nodes,bool stitching = false)
{

        //diag.InitialScale
        
        //image width
        double width = 0;
        //image height
        double height = 0;

        //Set Deafult values
        width = b.Width;
        height = b.Height;
        Point BitmapViewPos = new Point(b.X, b.Y);

        if (!((BO.FTA.FaultTree)model.SelectedItem).IsSummaryBoxVisible && (res == null || res.ISRootPage))
        {
            //Find summary node
            FTGateData gd = nodes[1];//model.FaultTreeDiagramMng
            Node localRemarksnode = diag.PartManager.FindNodeForData(gd, diag.Model);

            //Get Right postion of the last Node
            Node RightLastNode = null; // = diag.Panel.Diagram.Nodes.Last();
            Node LeftLastNode = null;
            foreach (Node n in diag.Panel.Diagram.Nodes)
            {

                if (((FTGateData)n.Data).GateDataType == FTGateType.SummaryBox)
                    continue;
                if (RightLastNode == null || LeftLastNode == null)
                {
                    RightLastNode = n;
                    LeftLastNode = n;
                }
                else
                {
                    if (RightLastNode.Location.X < n.Location.X)
                        RightLastNode = n;
                    if (LeftLastNode.Location.X > n.Location.X)
                        LeftLastNode = n;
                }
            }

            //Check Summary box position
            //when Summary box position out of the diagram boundaries neew calculate image width
            if (localRemarksnode.Location.X < 0)
            {
                double abs = System.Math.Abs(localRemarksnode.Location.X);
                if (RightLastNode.Location.X == 0)
                {
                    width = RightLastNode.Location.X + RightLastNode.ActualWidth + localRemarksnode.ActualWidth + 30;
                    BitmapViewPos = new Point(localRemarksnode.Location.X - 10, b.Y);
                }
                else
                {
                    width = RightLastNode.Location.X + RightLastNode.ActualWidth + abs; //localRemarksnode.ActualWidth;
                    BitmapViewPos = new Point(localRemarksnode.Location.X, b.Y);
                }
                //width = RightLastNode.Location.X + RightLastNode.ActualWidth +  10;

            }
            else
            {
                width = RightLastNode.Location.X + RightLastNode.ActualWidth;
            }

        }




        int dpi = 120;  // 96 dpi has dithering, 180 dpi gives very good quality
        double dpis = dpi / 96.0;

        width = width * dpis;
        height = height * dpis;
        //Scale
        double s = 1.0;
        width *= s;
        height *= s;

        //Jpeg lib using
        //http://www.nwoods.com/forum/forum_posts.asp?TID=3677&KW=jpeg&PID=15310&title=saving-image-problem-background#15310

        //Create Bitmap Source
        BitmapSource source = null;
        <span style="font-size: 12px; line-height: 1.4;">source = diag.Panel.MakeBitmap(new System.Windows.Size(width, height), dpi, BitmapViewPos, s);</span>


        
        // Convert original image to grayscale.
        FormatConvertedBitmap oBmpConv = new FormatConvertedBitmap();
        oBmpConv.BeginInit();
        oBmpConv.Source = source;

       
        BitmapPalette myPalette = new BitmapPalette(source, 256);
        oBmpConv.DestinationPalette = myPalette;
        oBmpConv.DestinationFormat = PixelFormats.Indexed8;

        oBmpConv.EndInit();


        return oBmpConv;
    }

Hi,
Our all png files more than 800k wide

Unfortunately i can’t provide you working project in order to reproduce this problem , but i can say you that my BLL layer create all nodes and link in the same way and binding model to diagram working in the same way too only my XAML templates more complicated structure .

My Dev environment exactly same (WPF 4.0 and VS2010 on a Windows 7 x64 system)


Thx