Monday, August 22, 2022

Generating Drawing Thumbnail/Preview Image in Side Database

With AutoCAD .NET API, it is quite common practice that we use side database to create a new drawing file, or update an existing drawing file. One of the issues with using side database to update drawing file is that the thumbnail/preview image in the drawing file either does not exist, or get lost when the drawing file opened as side database is saved (via Database.SaveAs() method).

A recent post in the .NET API discussion forum asks how to generate drawing file's thumbnail image in side database, This led me to recall I post an article here a while ago about how to get the image of a block. I thought it might be used as solution for this newly raised question. So, I fired up Visual Studio and put together some code quickly to see if it is doable.

If you have read my previous article, you can see I used Autodesk.AutoCAD.Internal.Utils.GetBlockImage() to generate a block image. This method takes an ObjectId of a BlockTableRecord. So, I thought, if I want to generate a image of the drawing, it means the BlockTableRecord should be the ModelSpace's ObjectId. With this in mind, here is my code that shows how to create a new drawing file with a side database. When the side database is created, some entities are added into ModelSpace, and then the image of the ModelSpace is created and assigned to Database.ThumbnailBitmap property before the side database is saved as drawing file.

Here is the code for using side database to create a drawing file:

using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.Internal;
using System;
 
namespace MiscTest
{
    public class SideDbCreation
    {
        public static void CreateDrawFromSideDatabase(
            string fileName, Action<Database> addEntityActionbool createThumnail = true)
        {
            using (var db = new Database(truetrue))
            {
                if (addEntityAction != null)
                {
                    addEntityAction(db);
                    if (createThumnail)
                    {
                        CreateThumnailInSideDatabase(db);
                    }
                }
 
                if (System.IO.File.Exists(fileName)) System.IO.File.Delete(fileName);
 
                db.SaveAs(fileName,DwgVersion.Current);
            }
        }
 
        public static void AddEntitiesInDatabase(Database db)
        {
            using (var tran=db.TransactionManager.StartTransaction())
            {
                var model = (BlockTableRecord)tran.GetObject(
                    SymbolUtilityServices.GetBlockModelSpaceId(db), OpenMode.ForWrite);
 
                CreateLine(
                    new Point3d(0, 0, 0), new Point3d(100, 0, 0), model, tran);
                CreateLine(
                    new Point3d(100, 0, 0), new Point3d(100, 100, 0), model, tran);
                CreateLine
                    (new Point3d(100, 100, 0), new Point3d(0, 100, 0), model, tran);
                CreateLine(
                    new Point3d(0, 100, 0), new Point3d(0, 0, 0), model, tran);
                CreateLine(
                    new Point3d(0, 0, 0), new Point3d(100, 100, 0), model, tran);
                CreateLine(
                    new Point3d(0, 100, 0), new Point3d(100, 0, 0), model, tran);
 
                tran.Commit();
            }
        }
 
        private static void CreateLine(
            Point3d startPt, Point3d endPt, BlockTableRecord model, Transaction tran)
        {
            var line = new Line(startPt, endPt);
            line.SetDatabaseDefaults(model.Database);
            model.AppendEntity(line);
            tran.AddNewlyCreatedDBObject(line, true);
        }
 
        private static void CreateThumnailInSideDatabase(Database db)
        {
            var cl = Autodesk.AutoCAD.Colors.Color.FromColor(
                System.Drawing.Color.WhiteSmoke);
            var blkId = SymbolUtilityServices.GetBlockModelSpaceId(db);
            var imgPtr = Utils.GetBlockImage(blkId, 100, 100, cl);
            using (var image = System.Drawing.Image.FromHbitmap(imgPtr))
            {
                db.ThumbnailBitmap = image;
            }
        }
    }
}

This is the CommandMethod to get the work done:

[CommandMethod("SideDbDwg")]
public static void CreateDrawingFromSideDb()
{
    var dwg = CadApp.DocumentManager.MdiActiveDocument;
    var ed = dwg.Editor;
 
    try
    {
        string fileName = @"E:\Temp\SideDbDrawing.dwg";
        SideDbCreation.CreateDrawFromSideDatabase(
            fileName, SideDbCreation.AddEntitiesInDatabase, true);
        ed.WriteMessage($"\nDrawing has been created at:\n{fileName}\n");
    }
    catch(System.Exception ex)
    {
        ed.WriteMessage(
            $"\nError: {ex.Message}\n");
    }
}

See the video clip below:


While I did not have time to try to use side database to update an existing drawing and then re-generate the thumbnail image, I do not see why it would not work.

Also, in this sample code I simply arbitrarily choose the image size of 100 x 100. I can be smaller or larger, I suppose. If you update existing drawing, there is likely an existing thumbnail image, so you can use the Database.ThumbnailBitmap property to get the size of the existing image and use the size for your new Thumbnail image. 

While the code is really simple, but to be warned: the code is at the mercy of the Autodesk.AutoCAD.Internal namespace, which Autodesk is free to break without warning (well, the chances are very low, unless the .NET API is subject to drastic changes for particular reasons

Followers

About Me

My photo
After graduating from university, I worked as civil engineer for more than 10 years. It was AutoCAD use that led me to the path of computer programming. Although I now do more generic business software development, such as enterprise system, timesheet, billing, web services..., AutoCAD related programming is always interesting me and I still get AutoCAD programming tasks assigned to me from time to time. So, AutoCAD goes, I go.