Get Type Id and Preview Image

It seems like there is an infinite amount of new functionality in the Revit 2011 API.
Here is another little item that I was not aware of before, even though it is listed clearly in the What’s New section of the Revit API help file RevitAPI.chm, which says:

Extract image of an ElementType

The new method ElementType.GetPreviewImage extracts the preview image of an Element Type. This image is similar to what is seen in the Revit UI when selecting the type of an element. You can specify the size of the image in pixels.

Here is a question that deals with retrieval of the preview image and also the use of the new Element.GetTypeId method, which returns the element id of the given element’s type.
That obviously only makes sense for an element that has a type assigned to it, for instance a family instance.

Question: I am trying to use the ElementType.GetPreviewImage method.
I doing so, I also ran into an issue with the Element.GetTypeId method.
Do you have a sample of using these two methods?

Answer: These two methods do not necessarily have anything to do with each other per se, but it is of course possible to grab all family instances in the model, ask each for its element type using GetTypeId, and then ask the element type for its preview image.
In case you are confused about the relationships of families, symbols and instances: a family is a collection of types. In the Revit 2011 API, they are represented by the ElementType class, which is a super class for all kinds of element types, and its subclass FamilySymbol, which specifically represents an element type that comes from a family. The ElementType class used to be named Symbol in previous versions of the API.

When you insert an instance of a symbol into the model, it is represented by a family instance object. You can have many instances making use of the same element type, e.g. eight chairs or a hundred windows of the same type.

The Element.GetTypeId method returns the element id of the given element’s type, if that makes any sense for the given element. This does make sense for family instances.

To demonstrate the use of the GetTypeId and GetPreviewImage methods, I implemented a new external command CmdPreviewImage in The Building Coder sample project, which does the following:

  • Retrieve all family instances using a filtered element collector.
  • Query each instance for its element type using GetTypeId.
  • Query each type for its preview image using GetPreviewImage.
  • Encode the returned bitmap into JPEG format, store it in an external file, and display it to the user.

I had to add two new references to the PresentationCore and WindowsBase .NET assemblies to gain access to some .NET image processing functionality. The following helper method makes use of this to convert a Bitmap instance to a BitmapSource:


static BitmapSource ConvertBitmapToBitmapSource(
  Bitmap bmp )
{
  return System.Windows.Interop.Imaging
    .CreateBitmapSourceFromHBitmap(
      bmp.GetHbitmap(),
      IntPtr.Zero,
      Int32Rect.Empty,
      BitmapSizeOptions.FromEmptyOptions() );
}

The command class is defined using a read-only transaction mode and a manual regeneration option, since no changes are applied to the model:


  [Transaction( TransactionMode.ReadOnly )]
  [Regeneration( RegenerationOption.Manual )]

Here is the command mainline code from the Execute method:


UIApplication uiapp = commandData.Application;
UIDocument uidoc = uiapp.ActiveUIDocument;
Document doc = uidoc.Document;
 
FilteredElementCollector collector
  = new FilteredElementCollector( doc );
 
collector.OfClass( typeof( FamilyInstance ) );
 
foreach( FamilyInstance fi in collector )
{
  Debug.Assert( null != fi.Category,
    "expected family instance to have a valid category" );
 
  ElementId typeId = fi.GetTypeId();
 
  ElementType type = doc.get_Element( typeId )
    as ElementType;
 
  Size imgSize = new Size( 200, 200 );
 
  Bitmap image = type.GetPreviewImage( imgSize );
 
  // encode image to jpeg for test display purposes:
 
  JpegBitmapEncoder encoder
    = new JpegBitmapEncoder();
 
  encoder.Frames.Add( BitmapFrame.Create(
    ConvertBitmapToBitmapSource( image ) ) );
 
  encoder.QualityLevel = 25;
 
  string filename = "a.jpg";
 
  FileStream file = new FileStream(
    filename, FileMode.Create, FileAccess.Write );
 
  encoder.Save( file );
  file.Close();
 
  Process.Start( filename ); // test display

I ran this command in the following minimal sample model with a wall with a door, a window and an opening in it:

Model of a wall with a door and a window

It therefore includes just two family instances, one each for the door and the window, and displays one 200 x 200 image for each for them, just as we requested:

Door type preview image
Window type preview image

On my system, the call to Process.Start pops up the Windows fax and picture viewer for each preview image it displays.

If you do not want to see the same image repeated multiple times for a type that is reused repeatedly in the model, you could add a check to skip ids of duplicate element types in the loop.
You could also name each image file individually, for instance using the type name or other data.
I did not add that here to keep the code as simple as possible to highlight the main principles.

Here is
version 2011.0.66.0
of The Building Coder sample source code and Visual Studio solution including the new command.

Addendum: In answer to Paul’s comment below, Harry Mattison points out that Revit does not have preview images for detail components.
For instance, here is an example of brick detailing, which displays no preview in the user interface:

No preview image for brick detail

Model objects such as a desk, on the other hand, display the preview image when selected:

Preview image of a desk


Comments

12 responses to “Get Type Id and Preview Image”

  1. Is there a special technique for getting the preview image for a detail component? Whenever I use the following code
    ElementType et = activedocument.get_Element(new ElementId(elementID)) as ElementType;
    Bitmap img = et.GetPreviewImage(new Size(128, 128));
    get preview always returns null for detail components but the model components work fine.

  2. Dear Paul,
    Please see the addendum from Harry that I just added above.
    Cheers, Jeremy.

  3. jude2012 Avatar
    jude2012

    hi,can i use this method to get the previewimage for each family symbol in a specify family?
    (the problem is i’ve list all the family symbols in a family ,and i want to show a priview image next to each family symbol,is it possibl?)

  4. Dear Jude,
    Sure, that is exactly what this functionality is intended for.
    Cheers, Jeremy.

  5. Hi..Jeremy
    For Model Group, I amn’t able to get preview image. Revit return null only.
    Please help me,
    Thanks

  6. Dear Sangsen,
    I guess this method is intended to be used with families and its symbols, and not with model groups.
    Maybe you can create your own screen snapshots and use them for model groups.
    Cheers, Jeremy.

  7. Dear Sir
    I am trying to create images using GetPreviewImage method.
    I need to show images of all families which i have in one folder..for which i need to load each and every family and get its first image and saving it on one location..Next time I am getting from that location.
    But for first time If I have 4000 families then it is not feasible to load these many families and get its image by its family instance

  8. Dear Mayur,
    I find that perfectly feasible. You may need to drive it as an intelligent batch, keeping track what has already been processed and what still needs to be done, in case you run into memory or other problems.
    Here is a related example which uses the ExportImage instead of GetPreviewImage for the task you describe:
    http://thebuildingcoder.typepad.com/blog/2013/08/setting-a-default-3d-view-orientation.html
    Cheers, Jeremy.

  9. Hi Jeremy,
    Thanx for this enlightening post I found acquiring the family previews easy.
    However, is it also possible to get the preview image of a system family, say a wall?
    cheers,
    Fabs

  10. Dear Fabs,
    Thank you for the appreciation.
    I am glad you found the post enlightening and the task easy to achieve.
    If you look at the code above, you see that it hinges on the ElementType.GetPreviewImage method.
    So, for a given instance element, you access its type via the GetTypeId method and retrieve the preview image from that.
    For a standard FamilyInstance element, the associated type will be a FamilySymbol.
    System family instances such as walls also have type, and they can also be accessed via the GetTypeId method.
    For a wall, the type would be a WallType.
    The RevitAPI.chm description of the ElementType.GetPreviewImage method states:
    “Get the preview image of an element. This image is similar to what is seen in the Revit UI when selecting the type of an element.”
    As said, ElementType should be available for system types as well, e.g. walls.
    Do they show a preview image in the UI?
    If they do, the exact same code as above may well work.
    Simply replace FamilyInstance by Element, and check whether GetTypeId returns a valid type.
    I hope helps and is is clear enough for you to understand.
    Cheers, Jeremy.

  11. Frank Halliday Avatar
    Frank Halliday

    Thanx Jeremmy I managed to work it out before you replied, I should have probed a little deeper…
    if(element.Category.Name.Contains(“Wall”))
    {
    Wall wall = element as Wall;
    ElementId typeId = wall.GetTypeId();
    type = rvtDoc.GetElement(typeId) as ElementType;
    }
    now I am after the preview image of unloaded families in a form listview. I tried doing a load family and then a transaction rollback, however I don’t think that can do the trick as I couldn’t get either the family instance or element type and I am too intimidated by the IextractImage Interface to implement it. I saw somebody elses post somewhere with “spaghetti” code which I was loathe to emulate.
    Any pointers?
    cheers, fabs

  12. Dear Fabs,
    Nope, sorry. Where did you see that spaghetti code?
    Cheers,
    Jeremy

Leave a Reply to jude2012Cancel reply

Discover more from Autodesk Developer Blog

Subscribe now to keep reading and get access to the full archive.

Continue reading