Taking a snapshot of the AutoCAD model using .NET

This topic is a follow-up to the previous post dealing with offscreen rendering, and was suggested (and is based on code provided) by Fenton Webb, a member of DevTech Americas who has just moved across to San Rafael. Fenton was until recently part of DevTech EMEA, working from the UK.

The basic technique is similar to the one used in the previous post: we use the graphics system to create an "offscreen device", which we then set up and request to create a snapshot of our model. This can work on graphical objects stored in any AutoCAD database, but in this case we use it to capture an image of the contents of the active drawing's modelspace (after, once again, adding a sphere to it).

To spice up the results a little, I added the option to specify a particular visual style for the output. I've inserted the created images at the bottom (as before, you will need to add a particular material to the current drawing in order to get exactly the same results I as I have).

Here's the C# code:

using Autodesk.AutoCAD.ApplicationServices;

using Autodesk.AutoCAD.DatabaseServices;

using Autodesk.AutoCAD.EditorInput;

using Autodesk.AutoCAD.GraphicsInterface;

using Autodesk.AutoCAD.GraphicsSystem;

using Autodesk.AutoCAD.Runtime;

using Autodesk.AutoCAD.Interop;

using System.Drawing;

namespace OffscreenImageCreation

{

  public class Commands

  {

    [CommandMethod("OSS")]

    static public void OffscreenSnapshot()

    {

      CreateSphere();

      SnapshotToFile(

        "c:\\sphere-Wireframe2D.png",

        VisualStyleType.Wireframe2D

      );

      SnapshotToFile(

        "c:\\sphere-Hidden.png",

        VisualStyleType.Hidden

      );

      SnapshotToFile(

        "c:\\sphere-Basic.png",

        VisualStyleType.Basic

      );

      SnapshotToFile(

        "c:\\sphere-ColorChange.png",

        VisualStyleType.ColorChange

      );

      SnapshotToFile(

        "c:\\sphere-Conceptual.png",

        VisualStyleType.Conceptual

      );

      SnapshotToFile(

        "c:\\sphere-Flat.png",

        VisualStyleType.Flat

      );

      SnapshotToFile(

        "c:\\sphere-Gouraud.png",

        VisualStyleType.Gouraud

      );

      SnapshotToFile(

        "c:\\sphere-Realistic.png",

        VisualStyleType.Realistic

      );

    }

    static public void CreateSphere()

    {

      Document doc =

        Application.DocumentManager.MdiActiveDocument;

      Database db = doc.Database;

      Editor ed = doc.Editor;

      Transaction tr =

        doc.TransactionManager.StartTransaction();

      using (tr)

      {

        BlockTable bt =

          (BlockTable)tr.GetObject(

            db.BlockTableId,

            OpenMode.ForRead

          );

        BlockTableRecord btr =

          (BlockTableRecord)tr.GetObject(

            bt[BlockTableRecord.ModelSpace],

            OpenMode.ForWrite

          );

        Solid3d sol = new Solid3d();

        sol.CreateSphere(10.0);

        const string matname =

          "Sitework.Paving - Surfacing.Riverstone.Mortared";

        DBDictionary matdict =

          (DBDictionary)tr.GetObject(

            db.MaterialDictionaryId,

            OpenMode.ForRead

          );

        if (matdict.Contains(matname))

        {

          sol.Material = matname;

        }

        else

        {

          ed.WriteMessage(

            "\nMaterial (" + matname + ") not found" +

            " - sphere will be rendered without it.",

            matname

          );

        }

        btr.AppendEntity(sol);

        tr.AddNewlyCreatedDBObject(sol, true);

        tr.Commit();

      }

      AcadApplication acadApp =

        (AcadApplication)Application.AcadApplication;

      acadApp.ZoomExtents();

    }

    static public void SnapshotToFile(

      string filename,

      VisualStyleType vst

    )

    {

      Document doc =

        Application.DocumentManager.MdiActiveDocument;

      Editor ed = doc.Editor;

      Database db = doc.Database;

      Manager gsm = doc.GraphicsManager;

      // Get some AutoCAD system variables

      int vpn =

        System.Convert.ToInt32(

          Application.GetSystemVariable("CVPORT")

        );

      // Get AutoCAD's GS view for this document...

      View gsv =

        doc.GraphicsManager.GetGsView(vpn, true);

      // ... but create a new one for the actual snapshot

      using (View view = new View())

      {

        // Set the view to be just like the one

        // in the AutoCAD editor

        view.Viewport = gsv.Viewport;

        view.SetView(

          gsv.Position,

          gsv.Target,

          gsv.UpVector,

          gsv.FieldWidth,

          gsv.FieldHeight

        );

        // Set the visual style to the one passed in

        view.VisualStyle = new VisualStyle(vst);

        Device dev =

          gsm.CreateAutoCADOffScreenDevice();

        using (dev)

        {

          dev.OnSize(gsm.DisplaySize);

          // Set the render type and the background color

          dev.DeviceRenderType = RendererType.Default;

          dev.BackgroundColor = Color.White;

          // Add the view to the device and update it

          dev.Add(view);

          dev.Update();

          using (Model model = gsm.CreateAutoCADModel())

          {

            Transaction tr =

              db.TransactionManager.StartTransaction();

            using (tr)

            {

              // Add the modelspace to the view

              // It's a container but also a drawable

              BlockTable bt =

                (BlockTable)tr.GetObject(

                  db.BlockTableId,

                  OpenMode.ForRead

                );

              BlockTableRecord btr =

                (BlockTableRecord)tr.GetObject(

                  bt[BlockTableRecord.ModelSpace],

                  OpenMode.ForRead

                );

              view.Add(btr, model);

              tr.Commit();

            }

            // Take the snapshot

            Rectangle rect = view.Viewport;

            using (Bitmap bitmap = view.GetSnapshot(rect))

            {

              bitmap.Save(filename);

              ed.WriteMessage(

                "\nSnapshot image saved to: " +

                filename

              );

              // Clean up

              view.EraseAll();

              dev.Erase(view);

            }

          }

        }

      }

    }

  }

}

And here are the images created by the OSS command, listed by their visual style type...

Wireframe2D:

spherewireframe2d

Hidden:

spherehidden

Basic:

spherebasic

ColorChange:

spherecolorchange

Conceptual:

sphereconceptual

Flat:

sphereflat

Gouraud:

spheregouraud

Realistic:

sphererealistic

Update: an improved version of the above code is now available in this follow-up post.

9 responses to “Taking a snapshot of the AutoCAD model using .NET”

  1. If using GetGsView() to create a view, it will show 3D UI background. How can we solve this problem? Thanks!

  2. Thie above code doesn't use AutoCAD's GS View directly - it just gets the view parameters from it. You should be fine if you follow the above example, creating a new View and using what you need from AutoCAD's.

  3. Thanks for you quick reply.
    I do not want users to konw the background change. What can I do?
    one more question.
    How can I get the snap shot in the paper space?
    Thanks again!

  4. I'm afraid I don't understand the question... sorry.

    As for taking a snapshot of paperspace, just try adding it to the view instead of the modelspace.

  5. Ok, I am trying to make my question clear.
    when you use GetGsView() to get the view with visual style 2dwireframe, do you find the acad background color is changed from black to gray?
    What can we do to avoid this change?
    Wish clear enough this time.
    Thanks!

  6. OK, now I understand the problem...

    Yes - calling GetGsView(vpn, true) will create a new 3D GS View, if one doesn't already exist. The default colour for these views' background is grey. If you pass false as the second argument, the view will not get created if it doesn't exist (it will be null), which means we can't use it to get/set the view parameters.

    The good news is that there's a function that does just that (one that I had missed). You can replace all the GetGsView()-related code with this line, which comes after we create the View object:

    gsm.SetViewFromViewport(view, vpn);

    This seems to have the same result as the previous code, with the added benefit of not creating a new 3D View with a grey backrgound to disturb your users. 🙂

    I'll create a new post with the updated code sometime next week.

    Thanks!

  7. Thanks a million.
    I will try that function.
    I am trying to get the preview of the geometries with setting "display", "extents" or "window" in Model space and paper space. The conception " display", "extents" and "window" here is the same as that in Plot dialog.
    I want to know if this sample is a feasible approach to do that.
    Thanks again!

  8. It should be, but the devil is in the detail when it comes to this kind of problem.

    Good luck!

    Kean

  9. Great! It works.
    I got a black rectangle area in the snapshot when I create a new view with layout in paper space. The black area seems like the viewport in the layout. Could you provide some ideas to me?
    Thanks in advance!

Leave a Reply to Robin Cancel reply

Your email address will not be published. Required fields are marked *