两种方式获取revit族文件预览缩略图

问题描述

想做一个族库管理插件,其中有一个功能是预览其缩略图.

解决方案1

revit api中有一个ElementType.GetPreviewImage方法,ElementType的常用子类就是familySymbol

需要注意的是GetPreviewImage返回的是一个Bitmap,在winform中是直接可以用于pictureBox的image控件的,

但是wpf中的image控件的source一般接受的是一个BitmapImage.

bitmap和bitmapimage的区别以及如何相互转换在此不说,搜一搜即可,但要注意一点:

bitmap转换为bitmapImage或者bitmap.save()时,一定要保证创建bitmap的stream没有关闭,也就是说要避免使用using语句!

 解决方案2

不使用任何revit api,使用System.IO.Packaging.StorageInfo的GetStreams方法,以下是链接:

https://thebuildingcoder.typepad.com/blog/2010/06/open-revit-ole-storage.html

他提供了一个示例文件的下载:

https://thebuildingcoder.typepad.com/files/openrevitolestorage.zip

简单概括下原理:反射System.IO.Packaging.StorageRoot的Open方法获取rfa文件的package信息,其中有一个叫做RevitPreview4.0的就存储着预览缩略图信息.将其读取为byte[],然后跳过revit的metadata,得到缩略图的原始二进制数据,

接下来就是byte[]转BitmapImage或者Bitmap的问题了,同样的要注意在某些地方避免使用using语句

抛砖引玉的代码

提供如何解析rfa文件和获得其跳过metadata后的起始位置的两个方法的代码:

        /// 
        ///     rfa等格式实际上是一个package,需通过StorageInfo来访问,但是要获得StorageInfo必须
        ///     通过反射调用StorageRoot的一个Open方法来获得之
        /// 
        /// 
        /// 
        private byte[] ParseRevitPreview4_0(string filename)
        {
            var srType = typeof(StorageInfo).Assembly.GetType("System.IO.Packaging.StorageRoot");

            if (srType?.InvokeMember("Open",
                BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.InvokeMethod
                , null, null, new object[]{filename,
                    FileMode.Open,FileAccess.Read,FileShare.Read}) is StorageInfo stInfo)
            {
                foreach (StreamInfo streamInfo in stInfo.GetStreams())
                {
                    if (streamInfo.Name.Equals("RevitPreview4.0", StringComparison.Ordinal))
                    {
                        using (var reader = streamInfo.GetStream(FileMode.Open, FileAccess.Read))
                        {
                            var imageData = new byte[reader.Length];
                            reader.Read(imageData, 0, imageData.Length);
                            return imageData;
                        }
                    }
                }
            }


            return default;
        }

        /// 
        ///     RevitPreview4.0的二进制流中需要跳过revit的一些metadata,来获得图片的起始位置
        /// 
        /// 
        /// 
        private int GetPngStartingOffset(byte[] rawData)
        {
            bool markerFound = false;
            int startingOffset = 0;
            int previousValue = 0;
            using (MemoryStream ms = new MemoryStream(rawData))
            {
                for (int i = 0; i < rawData.Length; i++)
                {
                    int currentValue = ms.ReadByte();
                    // possible start of PNG file data
                    if (currentValue == 137)   // 0x89
                    {
                        markerFound = true;
                        startingOffset = i;
                        previousValue = currentValue;
                        continue;
                    }

                    switch (currentValue)
                    {
                        case 80:   // 0x50
                            if (markerFound && (previousValue == 137))
                            {
                                previousValue = currentValue;
                                continue;
                            }
                            markerFound = false;
                            break;

                        case 78:   // 0x4E
                            if (markerFound && (previousValue == 80))
                            {
                                previousValue = currentValue;
                                continue;
                            }
                            markerFound = false;
                            break;

                        case 71:   // 0x47
                            if (markerFound && (previousValue == 78))
                            {
                                previousValue = currentValue;
                                continue;
                            }
                            markerFound = false;
                            break;

                        case 13:   // 0x0D
                            if (markerFound && (previousValue == 71))
                            {
                                previousValue = currentValue;
                                continue;
                            }
                            markerFound = false;
                            break;

                        case 10:   // 0x0A
                            if (markerFound && (previousValue == 26))
                            {
                                return startingOffset;
                            }
                            if (markerFound && (previousValue == 13))
                            {
                                previousValue = currentValue;
                                continue;
                            }
                            markerFound = false;
                            break;

                        case 26:   // 0x1A
                            if (markerFound && (previousValue == 10))
                            {
                                previousValue = currentValue;
                                continue;
                            }
                            markerFound = false;
                            break;
                    }
                }
            }
            return 0;
        }

 

你可能感兴趣的:(revit,C#,revit,预览缩略图)