Save a diagram to Image File


I’ve been asked a couple of times now about how to save one of our UML diagrams out to an image file. We don’t have a menu item that does that exact thing in the diagrams themselves. We of course support a select-all, copy, then paste which satisfies most, but a few customers have been asking how they can automate that process for documentation generation or what have you.

Turns out it is actually quite easy to write a simple extension to do exactly this.

Below is the code required to add a menu item that will appear as a context menu in any of the five UML diagrams shipping in VS2010 ( UML class, sequence, activity, component, and use case diagrams ).

The piece of “magic” in the code below is this line:

Diagram dslDiagram = Context.CurrentDiagram.GetObject<Diagram>();

You can ask an IDiagramContext to give you a Microsoft.VisualStudio.Modeling.Diagrams.Diagram object via the GetObject<>() method. For those of you familiar with the DSL programming model, this is indeed a DSL Diagram object, which gives you access to the public ( and documented ) DSL APIs that we have built the UML diagrams on.

We’ve tried to simplify the APIs needed to manipulate the UML object models, which is why we didn’t make the DSL underlying implementation more obvious.

Regardless, here’s the code needed to get a menu item called “Save To Image…” on your UML diagrams. Most of the code is manipulating the SaveFileDialog object. 🙂

This will work in the current RC build for VS2010.

Enjoy!

Cameron

using System;
using System.Linq;
using System.ComponentModel.Composition;
using Microsoft.VisualStudio.ArchitectureTools.Extensibility.Presentation;
using Microsoft.VisualStudio.ArchitectureTools.Extensibility.Uml;
using Microsoft.VisualStudio.Modeling.ExtensionEnablement;
using Microsoft.VisualStudio.Uml.Classes;
using Microsoft.VisualStudio.Modeling.Diagrams;
using System.Drawing;
using System.Drawing.Imaging;
using System.Windows.Forms;

namespace SaveToImage
{
    // Custom context menu command extension
    // See http://msdn.microsoft.com/en-us/library/ee329481(VS.100).aspx
    [Export( typeof( ICommandExtension ) )]
    [ClassDesignerExtension]

    [UseCaseDesignerExtension]
    [SequenceDesignerExtension]
    [ComponentDesignerExtension]
    [ActivityDesignerExtension]
    class CommandExtension : ICommandExtension
    {
        [Import]
        IDiagramContext Context { get; set; }

        public void Execute( IMenuCommand command )
        {
            Diagram dslDiagram = Context.CurrentDiagram.GetObject<Diagram>();

            if( dslDiagram != null )
            {
                SaveFileDialog dialog = new SaveFileDialog();
                dialog.AddExtension = true;
                dialog.DefaultExt = "image.bmp";
                dialog.Filter = "Bitmap ( *.bmp )|*.bmp|JPEG File ( *.jpg )|*.jpg|Enhanced Metafile (*.emf )|*.emf|Portable Network Graphic ( *.png )|*.png";
                dialog.FilterIndex = 1;
                dialog.Title = "Save Diagram to Image";

                if( dialog.ShowDialog() == DialogResult.OK && !string.IsNullOrEmpty( dialog.FileName))
                {
                    Bitmap bitmap = dslDiagram.CreateBitmap( dslDiagram.NestedChildShapes, Diagram.CreateBitmapPreference.FavorClarityOverSmallSize );
                    bitmap.Save( dialog.FileName, GetImageType( dialog.FilterIndex ));
                }
            }
        }

        public void QueryStatus( IMenuCommand command )
        {
            if( Context.CurrentDiagram != null && Context.CurrentDiagram.ChildShapes.Count() > 0 )
            {
                command.Enabled = true;
            }
            else
            {
                command.Enabled = false;
            }
        }

        public string Text
        {
            get { return "Save To Image…"; }
        }

        private ImageFormat GetImageType( int filterIndex )
        {
            ImageFormat result = ImageFormat.Bmp;

            switch( filterIndex )
            {
                case 2:
                    result = ImageFormat.Jpeg;
                    break;
                case 3:
                    result = ImageFormat.Emf;
                    break;
                case 4:
                    result = ImageFormat.Png;
                    break;
            }
            return result;
        }
    }
}

Comments (8)

  1. Anonymous says:

    Do you have a link which talks about creating new extension in VS2010?

  2. If you are interested in the extension points that we are enabling with all the visualization and modeling tools in 2010, check out this link:

    http://msdn.microsoft.com/en-us/library/ee329484(VS.100).aspx

    If you are looking for VS2010 extensibility in general, check out this one:

    http://msdn.microsoft.com/en-us/library/bb166441(VS.100).aspx

    And if you are just looking for more general VS information, I also recommend checking out the VS team blog here:

    http://blogs.msdn.com/visualstudio/default.aspx

    Cheers!

    Cameron

  3. Anonymous says:

    I couldn’t find this assembly.

    Microsoft.VisualStudio.Modeling.ExtensionEnablement

    I have VS2010 RC1.

  4. You need to be sure to install the VSVMSDK installed. Check out this post for more details. http://blogs.msdn.com/camerons/archive/2010/02/10/visual-studio-2010-visualization-and-modeling-sdk-rc.aspx

    I also recommend hitting the forums if you have further questions like this, as you’ll get a faster response. 🙂

    http://social.msdn.microsoft.com/Forums/en-US/vsarch/threads

    Thanks!

    Cameron

  5. Anonymous says:

    Is there any way to extend the layer diagram? Or is there any tool can help me to save the layer diagram as image?

  6. Anonymous says:

    Hey Jifeng,

    Cameron’s post above will work for layer diagrams as well. So you can

    1. Use copy/paste to save the diagram as an image.
    2. Use the sample code above to write a tool that will.

    We are currently working on some fairly extensive extensibility for the layer diagram. This will support

    1. Access to the layer model and the ability to create commands etc. much like the extensibility for the rest of our UML models like

    http://msdn.microsoft.com/en-us/library/ee329484

    1. Creation of custom validation rules to support your own architectural enforcement.

    Look for news and release information on that in the near future.

    Thanks

    Suhail

  7. John Calvert says:

    Thanks for the code sample, much appreciated. We experimented with this approach (built a VSIX and all) but found the fidelity of the resulting bitmaps to be too low so we are using print to PDF/XPS instead. It would be a big help to have advice on how to configure our project to auto-generate the image files (whether bitmap or PDF) whenever there is a Build of the modeling project. And auto-post these to TFS source control and/or the TFS team project portal.

  8. @John – Take a look at the "readonly" APIs for loading a model without having VS opened. I believe you should be able to do what you are sugggesting via those APS. Here's the link: msdn.microsoft.com/…/ee329477.aspx