Author Topic: Previews or Thumbnails  (Read 1202 times)

0 Members and 1 Guest are viewing this topic.

cmwade77

  • Swamp Rat
  • Posts: 1449
Previews or Thumbnails
« on: May 30, 2024, 02:40:45 PM »
I am trying to extract a preview or thumbnail from drawings without opening them, I have code that does well if the thumbnail is saved (i.e. it shows up in Windows Explorer), but if it isn't saved, it doesn't show up.

Yet, it sheet set manager, a preview can be shown just fine for the same drawing, so there has to be something that I am missing here. Here is my code as it stands:
Code - C#: [Select]
  1.  public static Bitmap? Thumbnail(this string drawingFilePath)
  2.  {
  3.      try
  4.      {
  5.          using (Database db = new Database(false, true))
  6.          {
  7.              db.ReadDwgFile(drawingFilePath, FileOpenMode.OpenForReadAndAllShare, true, null);
  8.              Bitmap? thumbnail = db.ThumbnailBitmap;
  9.              if (thumbnail == null)
  10.              {
  11.                  return PlaceholderThumbnail();
  12.              }
  13.              return thumbnail;
  14.          }
  15.      }
  16.      catch (System.Exception ex)
  17.      {
  18.          Application.DocumentManager.MdiActiveDocument.Editor.WriteMessage($"\nError extracting thumbnail: {ex.Message}");
  19.          return null;
  20.      }
  21.  }

Any ideas would be greatly appreciated.

retsameht

  • Newt
  • Posts: 22
Re: Previews or Thumbnails
« Reply #1 on: May 30, 2024, 04:26:13 PM »
If you don't see a thumbnail in Windows, it means there is no thumbnail for the file. That can happen if you open the DWG using ReadDwgFile() and save it without using the correct overload and arguments to SaveAs():

Code: [Select]
public void SaveAs(
    string fileName,
    bool bBakAndRename,    /// Must pass true for this argument.
    DwgVersion version,
    Autodesk.AutoCAD.DatabaseServices.SecurityParameters security
);

Sheet Set Manager must be generating the thumbnail in that case.

cmwade77

  • Swamp Rat
  • Posts: 1449
Re: Previews or Thumbnails
« Reply #2 on: May 30, 2024, 04:50:17 PM »
I think I must be missing something here, here is the code I have:

Code - C#: [Select]
  1.  public static Bitmap? Thumbnail(this Database db)
  2.  {
  3.      try
  4.      {
  5.          Bitmap? thumbnail = db.ThumbnailBitmap;
  6.          if (thumbnail == null)
  7.          {
  8.              db.SafeSave(true);
  9.              if (thumbnail == null)
  10.              {
  11.                  return PlaceholderThumbnail();
  12.              }
  13.          }
  14.          return thumbnail;
  15.      }
  16.      catch (System.Exception ex)
  17.      {
  18.          Application.DocumentManager.MdiActiveDocument.Editor.WriteMessage($"\nError extracting thumbnail: {ex.Message}");
  19.          return null;
  20.      }
  21.  }
  22.  
  23.  private static Bitmap PlaceholderThumbnail()
  24.  {
  25.      // Create a simple placeholder thumbnail
  26.      Bitmap thumbnail = new Bitmap(256, 256);
  27.      using (Graphics g = Graphics.FromImage(thumbnail))
  28.      {
  29.          g.Clear(Color.Gray);
  30.  
  31.          string text = "No Preview";
  32.          Font font = new Font("Arial", 24);
  33.          SizeF textSize = g.MeasureString(text, font);
  34.  
  35.          // Calculate the position to center the text
  36.          float x = (thumbnail.Width - textSize.Width) / 2;
  37.          float y = (thumbnail.Height - textSize.Height) / 2;
  38.  
  39.          g.DrawString(text, font, Brushes.White, new PointF(x, y));
  40.      }
  41.      return thumbnail;
  42.  }
  43.  
  44.  public static bool SafeSave(this Database db, bool KeepDate = false)
  45.  {
  46.      string filenameToMatch = db.Filename;
  47.  
  48.      try
  49.      {
  50.          DateTime Old = File.GetLastWriteTime(filenameToMatch);
  51.          if (!filenameToMatch.IsFileLocked())
  52.          {
  53.              db.SaveAs(filenameToMatch, true, DwgVersion.Current, null); // Overwrite the original file
  54.              return true;
  55.          }
  56.          else
  57.          {
  58.              Document activeDoc = Application.DocumentManager.MdiActiveDocument;
  59.              if (string.Equals(filenameToMatch, activeDoc.Database.Filename, StringComparison.OrdinalIgnoreCase))
  60.              {
  61.                  activeDoc.SendStringToExecute("_.qsave\n", false, false, false);
  62.                  return true;
  63.              }
  64.          }
  65.          if (KeepDate)
  66.          {
  67.              File.SetLastWriteTime(filenameToMatch, Old);
  68.          }
  69.      }
  70.      catch (Autodesk.AutoCAD.Runtime.Exception ex)
  71.      {
  72.          Application.ShowAlertDialog($"Error saving file: {ex.Message}");
  73.      }
  74.      return false;
  75.  }
  76.  

It's Alive!

  • Retired
  • Needs a day job
  • Posts: 8919
  • AKA Daniel
Re: Previews or Thumbnails
« Reply #3 on: May 30, 2024, 08:32:59 PM »
Isnít there a function CMLContentSearchPreviews.GetBlockTRThumbnail(btr);
Just pass in model space

cmwade77

  • Swamp Rat
  • Posts: 1449
Re: Previews or Thumbnails
« Reply #4 on: May 30, 2024, 08:35:20 PM »
How do I do that without opening the drawing and I want it in paperspace for specific layouts? Please keep in mind I am still very new to .NET

It's Alive!

  • Retired
  • Needs a day job
  • Posts: 8919
  • AKA Daniel
Re: Previews or Thumbnails
« Reply #5 on: May 30, 2024, 09:01:13 PM »
Code - C#: [Select]
  1. using (Database db = new Database(false, true))
Is opening the drawing, so we have some ambiguity on this definition.

If we are good with opening the db, you would pass in the objectid that represents the block table record for the space
Either modelspace or paperspace   

It's Alive!

  • Retired
  • Needs a day job
  • Posts: 8919
  • AKA Daniel
Re: Previews or Thumbnails
« Reply #6 on: May 30, 2024, 09:06:35 PM »
Itís not a trivial task, but you could try to unpack the .NET BlockView sample.
From there you can grab View.GetSnapShot, which returns a bitmap.

It's Alive!

  • Retired
  • Needs a day job
  • Posts: 8919
  • AKA Daniel
Re: Previews or Thumbnails
« Reply #7 on: May 30, 2024, 09:18:40 PM »
Here a version in Python if your feeling adventurous  :mrgreen:
https://www.theswamp.org/index.php?topic=59527.msg621035#msg621035

It's Alive!

  • Retired
  • Needs a day job
  • Posts: 8919
  • AKA Daniel
Re: Previews or Thumbnails
« Reply #8 on: May 30, 2024, 09:25:46 PM »
One last thing, if youíre going to reuse these in a GUI. You may wish to store the images in a SQL database
In SQLite you can store them as a blob, itís wicked fast (Boston accent)  :lmao:
I store a timestamp, name, path, and image as a blob

retsameht

  • Newt
  • Posts: 22
Re: Previews or Thumbnails
« Reply #9 on: May 31, 2024, 07:53:32 PM »
I think I must be missing something here, here is the code I have:

Code - C#: [Select]
  1.      activeDoc.SendStringToExecute("_.qsave\n", false, false, false);
  2.  

The above line doesn't execute until after your code returns control to AutoCAD. Unless it's being called from the application context, I would use the Editor's Command() method.

cmwade77

  • Swamp Rat
  • Posts: 1449
Re: Previews or Thumbnails
« Reply #10 on: June 03, 2024, 12:10:10 PM »
I think I must be missing something here, here is the code I have:

Code - C#: [Select]
  1.      activeDoc.SendStringToExecute("_.qsave\n", false, false, false);
  2.  

The above line doesn't execute until after your code returns control to AutoCAD. Unless it's being called from the application context, I would use the Editor's Command() method.
Except the drawing isn't open in the editor.

It's Alive!

  • Retired
  • Needs a day job
  • Posts: 8919
  • AKA Daniel
Re: Previews or Thumbnails
« Reply #11 on: June 03, 2024, 08:06:46 PM »
you can also use the publish to web, and just make the paper size tiny

cmwade77

  • Swamp Rat
  • Posts: 1449
Re: Previews or Thumbnails
« Reply #12 on: June 04, 2024, 01:36:00 PM »
I finally got some code working, please let me know if there are improvements that can be made to it:

Code - C#: [Select]
  1.         public static BitmapSource? GetLayoutThumbnail(string drawingPath, string layoutName)
  2.         {
  3.             BitmapSource? bmpSource = null;
  4.  
  5.             if (File.Exists(drawingPath))
  6.             {
  7.                 // Open the database in read-only mode
  8.                 Database db = new(false, true);
  9.                 using (db)
  10.                 {
  11.                     // Use FileShare.ReadWrite to avoid file sharing violations
  12.                     db.ReadDwgFile(drawingPath, FileShare.ReadWrite, true, null);
  13.                     using Transaction tr = db.TransactionManager.StartTransaction();
  14.                     DBDictionary layoutDict = (DBDictionary)tr.GetObject(db.LayoutDictionaryId, OpenMode.ForRead);
  15.                     foreach (DBDictionaryEntry entry in layoutDict)
  16.                     {
  17.                         Layout layout = (Layout)tr.GetObject(entry.Value, OpenMode.ForRead);
  18.                         if (layout.LayoutName == layoutName)
  19.                         {
  20.                             Bitmap? bitmap = layout.Thumbnail ?? db.Thumbnail();
  21.                             if (bitmap != null)
  22.                             {
  23.                                 bmpSource = ConvertToBitmapSource(bitmap);
  24.                             }
  25.                             break;
  26.                         }
  27.                     }
  28.                     tr.Commit();
  29.                 }
  30.             }
  31.             return bmpSource;
  32.         }
  33.  
  34.         public static Bitmap? Thumbnail(this Database db)
  35.         {
  36.             try
  37.             {
  38.                 Bitmap? thumbnail = db.ThumbnailBitmap;
  39.                 if (thumbnail == null)
  40.                 {
  41.                     db.SafeSave(true);
  42.                     if (thumbnail == null)
  43.                     {
  44.                         return PlaceholderThumbnail();
  45.                     }
  46.                 }
  47.                 return thumbnail;
  48.             }
  49.             catch (System.Exception ex)
  50.             {
  51.                 Application.DocumentManager.MdiActiveDocument.Editor.WriteMessage($"\nError extracting thumbnail: {ex.Message}");
  52.                 return null;
  53.             }
  54.         }
  55.  
  56.         private static BitmapImage ConvertToBitmapSource(System.Drawing.Bitmap bitmap)
  57.         {
  58.             using MemoryStream memoryStream = new();
  59.             bitmap.Save(memoryStream, System.Drawing.Imaging.ImageFormat.Bmp);
  60.             memoryStream.Position = 0;
  61.             BitmapImage bitmapImage = new();
  62.             bitmapImage.BeginInit();
  63.             bitmapImage.StreamSource = memoryStream;
  64.             bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
  65.             bitmapImage.EndInit();
  66.             bitmapImage.Freeze();
  67.             return bitmapImage;
  68.         }
  69.  
  70.         private static Bitmap PlaceholderThumbnail()
  71.         {
  72.             // Create a simple placeholder thumbnail
  73.             Bitmap thumbnail = new(256, 256);
  74.             using (Graphics g = Graphics.FromImage(thumbnail))
  75.             {
  76.                 g.Clear(Color.Gray);
  77.  
  78.                 const string text = "No Preview";
  79.                 Font font = new("Arial", 24);
  80.                 SizeF textSize = g.MeasureString(text, font);
  81.  
  82.                 // Calculate the position to center the text
  83.                 float x = (thumbnail.Width - textSize.Width) / 2;
  84.                 float y = (thumbnail.Height - textSize.Height) / 2;
  85.  
  86.                 g.DrawString(text, font, Brushes.White, new PointF(x, y));
  87.             }
  88.             return thumbnail;
  89.         }
  90.  

If the layout doesn't have a thumbnail, then it failes over to using a drawing preview from the drawing database and if that doesn't exist, it uses a placeholder that indicates no preview is available.