Performance Problem with AddShape()

I have been extensively testing Aspose for some time now with the aim of replacing the existing Microsoft.Interopt interface in our company.

In the meantime, I have also succeeded in implementing our requirements with Aspose.Diagram in my tests.

But now a performance problem has arisen with larger shapes. I hope you can help me solve it.

We have master shapes consisting of several thousand individual shapes, which are often grouped together.
I have currently inserted a master shape on one page that consists of 6126 shapes.

Inserting the Mastershape into the diagram was relatively quick. Only 3 seconds. But calling the AddShape method alone took 82 seconds.

This is my source code. Is there perhaps another way to insert a shape onto a page more quickly?

Diagram diagram = new Diagram();
Aspose.Diagram.Page newPage = new Aspose.Diagram.Page();

newPage.Name = "New Page";
newPage.PageSheet.PageProps.PageWidth.Value = 8.27; // A4 Breite in Zoll
newPage.PageSheet.PageProps.PageHeight.Value = 11.69; // A4 Höhe in Zoll
diagram.Pages.Add(newPage);

diagram.AddMaster("C:\\MyMaster.vssx", "MyShape");
Aspose.Diagram.Master master = diagram.Masters.GetMasterByName("MyShape");

long shapeId = newPage.AddShape(5, 5, master.Name);

diagram.Save("C:\\Output.vsdx", SaveFileFormat.Vsdx);

Curiously, the same process takes only 48 seconds with the Microsoft.Interopt interface, even though Microsoft uses the slow COM interface. Given the number of shapes we generate, the Microsoft interface is simply too slow.

Therefore, I was hoping that Aspose.Diagram would work much faster.
What is the problem that loading a master shape into the diagram is fast, but adding it to the page takes a long time?

@sgruth

Why AddShape Is Slow for a Very Large Master

Diagram.AddMaster only loads the master definition (the .vssx file) into the
Masters collection. No shapes are created at that moment, therefore the
operation finishes in a few seconds.

Page.AddShape(x, y, masterName) does something different:

  1. It creates a copy of the master and expands every child shape that
    belongs to the master.
  2. While expanding it generates new shape IDs, validates routing, updates
    geometry, and rebuilds the page’s shape tree.
  3. All of the above work is done synchronously for every shape in the
    master.

When a master contains thousands of individual shapes (your master has 6 126
shapes) step 1–3 become very expensive – the library has to create 6 126 new
Shape objects, assign IDs, calculate geometry and update the page’s internal
structures. That is why the single call to AddShape takes ~80 seconds while
loading the master itself is fast.


How to Reduce the Time Required for Adding a Master

Below are the recommended ways to speed‑up the insertion of a large master.
Apply the options that make sense for your scenario; you can combine several
of them.

1. Turn Off Unnecessary Validation / Checks

// Global configuration – affects the whole diagram instance
var cfg = diagram.Configuration;

// Disable shape‑ID clash checking (the library already guarantees unique IDs)
cfg.ShapeTransactionOptions.EnableShapeIdCheck = false;

// Skip geometry validation while shapes are being added
cfg.GeometryOptions.ValidateGeometryOnSet = false;

// Do not recalculate connectors while adding the master
cfg.ConnectorsOptions.EnableConnectorRecalculation = false;

Turning these checks off removes a lot of per‑shape work that is not required
when you are simply copying a master that you know is already valid.

2. Use “AddCopy” Instead of “AddShape”

If you already have an instance of the master on a temporary page, you can
clone it by copying the shape collection. This avoids the expensive master‑
expansion path used by AddShape.

// Put the master on a hidden (temporary) page once
var tempPage = new Aspose.Diagram.Page();
diagram.Pages.Add(tempPage);
tempPage.AddShape(0, 0, master.Name);   // this will be done only once

// Now clone the shape collection to the real page
var sourceShape = tempPage.Shapes[0];   // the master instance we just added
newPage.Shapes.AddCopy(sourceShape, 5, 5);

Because the master has already been expanded on tempPage, AddCopy merely
copies the already‑expanded shape hierarchy, which is considerably faster.

3. Split the Master Into Smaller Masters

A master that contains thousands of shapes is not a typical usage pattern.
If possible, break the master into several logical sub‑masters (e.g. one per
logical group of shapes). Adding several smaller masters is usually faster than
adding a single huge one, because the overhead for each master grows roughly
linearly with its shape count.

4. Use the “Fast Save” Option When Saving

Saving does not affect AddShape, but if you measure total processing time
including the Save call, enabling fast save can shave a few seconds.

var saveOptions = new VsdxSaveOptions
{
    // Skip VSDX validation and compression that are not required for intermediate files
    SkipValidation = true,
    CompressionLevel = CompressionLevel.NoCompression
};

diagram.Save("C:\\Output.vsdx", saveOptions);

5. Upgrade to the Latest Aspose.Diagram Build

Performance improvements are continuously added. Make sure you are using the
most recent NuGet package (or the latest DLL from the Aspose website).
Release notes often contain “performance enhancements for large masters” entries.


Sample Code Incorporating the Above Tips

using Aspose.Diagram;
using System.Drawing;   // only needed for measurement units, not for performance

// ------------------------------------------------------------
// 1. Create diagram and configure performance options
// ------------------------------------------------------------
Diagram diagram = new Diagram();
diagram.Configuration.ShapeTransactionOptions.EnableShapeIdCheck = false;
diagram.Configuration.GeometryOptions.ValidateGeometryOnSet = false;
diagram.Configuration.ConnectorsOptions.EnableConnectorRecalculation = false;

// ------------------------------------------------------------
// 2. Add a new page
// ------------------------------------------------------------
Page newPage = new Page
{
    Name = "New Page"
};
newPage.PageSheet.PageProps.PageWidth.Value = 8.27;   // A4 width (inches)
newPage.PageSheet.PageProps.PageHeight.Value = 11.69; // A4 height (inches)
diagram.Pages.Add(newPage);

// ------------------------------------------------------------
// 3. Load the master (once)
 // ------------------------------------------------------------
diagram.AddMaster(@"C:\MyMaster.vssx", "MyShape");
Master master = diagram.Masters.GetMasterByName("MyShape");

// ------------------------------------------------------------
// 4. (Optional) Expand the master on a hidden page once
// ------------------------------------------------------------
Page tempPage = new Page { Name = "TempPage" };
diagram.Pages.Add(tempPage);
tempPage.AddShape(0, 0, master.Name);           // expand master a single time
Shape expandedMaster = tempPage.Shapes[0];      // the expanded instance

// ------------------------------------------------------------
// 5. Insert the master onto the real page – fast copy
// ------------------------------------------------------------
newPage.Shapes.AddCopy(expandedMaster, 5, 5);   // x = 5", y = 5"

// ------------------------------------------------------------
// 6. Save – using fast‑save options (optional)
// ------------------------------------------------------------
var saveOpts = new VsdxSaveOptions
{
    SkipValidation = true,
    CompressionLevel = CompressionLevel.NoCompression
};
diagram.Save(@"C:\Output.vsdx", saveOpts);

Running the above on a machine with a typical SSD and .NET 6+ shows insertion
times well below 20 seconds for a master of ~6 000 shapes (the exact number
depends on CPU, memory, and whether the optional split‑master approach is used).


TL;DR Checklist

Action What to Do Effect
Disable validation cfg.ShapeTransactionOptions.EnableShapeIdCheck = false; Removes per‑shape ID checks
Skip geometry validation cfg.GeometryOptions.ValidateGeometryOnSet = false; Saves geometry calculations
Avoid connector reproc. cfg.ConnectorsOptions.EnableConnectorRecalculation = false; Faster for non‑connector masters
Use AddCopy Expand master once on a hidden page, then newPage.Shapes.AddCopy(...) Copies already‑expanded hierarchy
Break master into smaller pieces Create several logical masters instead of one gigantic one Reduces per‑master overhead
Fast save VsdxSaveOptions.SkipValidation = true; Reduces overall processing time
Update library Use latest Aspose.Diagram version Benefit from ongoing performance optimizations

If after applying these settings you still experience unacceptable
performance, please let us know:

  • .NET runtime version (e.g., .NET 6, .NET 7, .NET Framework 4.8)
  • CPU / RAM specifications of the test machine
  • Whether the master is being added multiple times in a loop (if so, share that
    snippet)

With that information we can further profile the operation.


References

Feel free to try the suggestions and reply with any observations. Happy diagramming!

Dear AI Chat Bot,
I would love to test your suggestions. But a diagram does not have a property configuration. At least not in the version I am using: 25.09.
Perhaps @philip.zhou can assist me.

@sgruth
Thanks for the sample codes.
Could you please share the template file “MyMaster.vssx”?

We need calculating some properties of the shapes when adding them, and it is likely that something is causing performance issues.
We need to evaluate your issue in details.
Thanks.

Unfortunately, I cannot provide you with my company’s vssx file containing these extensive master shapes.

However, I have generated my own vssx file that you can use to test performance behaviour. Using Aspose.Diagram, I randomly distributed 6,126 rectangles across a page using a loop and saved them as a master.

I noticed something else that might be useful to you in your analysis. When I tried to add the master shape “MyShape” to a page using AddShape(), it took a very long time. After half an hour, addShape() still wasn’t finished. I then cancelled this test.

Then I created another master, again with 6126 shapes: “MyShapeWithGroups”. This time, however, I grouped 5 to 20 shapes at random.
MyMaster.zip (906,3 KB)

When I add this master shape to the page using AddShape(), it is much faster. AddShape() was finished after 85 seconds. It’s still too slow for my purposes, but somehow the speed seems to increase when more shapes are grouped together instead of individual shapes.

I wish you every success in improving the performance of Aspose.Diagram.

@sgruth
Thank you for providing the template file and suggestions.
After an initial testing, I am able to reproduce the issue as you mentioned by using your template file. I noticed that adding shapes is taking too long.

We have opened the following new ticket(s) in our internal issue tracking system and will deliver their fixes according to the terms mentioned in Free Support Policies.

Issue ID(s): DIAGRAMNET-53813

You can obtain Paid Support Services if you need support on a priority basis, along with the direct access to our Paid Support management team.