Revit获取族预览图

最近做到和族库相关的功能需要获取到族文件的预览图,在RevitAPI中提供了ElementType.GetPreviewImage方法,但是前提就是你是在Revit里面操作的,并且已经拿到了Symbol对象实例,才可以调用此方法。然后在网上找了另外一种方式,通过读取Revit文件,在REVITPREVIEW4.0字段截取文件信息,将其转换为图片格式。

一、使用RevitAPI中ElementType.GetPreviewImage方法

[Autodesk.Revit.Attributes.Transaction(TransactionMode.Manual)]
    public class GetThumbnail : IExternalCommand
    {
        public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements)
        {
            var uidoc = commandData.Application.ActiveUIDocument;
            var doc = uidoc.Document;

            var elemRef = uidoc.Selection.PickObject(ObjectType.Element);
            var elem = doc.GetElement(elemRef) as FamilyInstance;
            var previewImage = elem.Symbol.GetPreviewImage(new Size(100, 100));

            return Result.Succeeded;
        }
    } 

二、使用System.IO.Packaging.StorageInfo.GetStreams方法 这种方式可以在不打开Revit文件的情况下,直接读取族文件的方式直接获取到族预览图。

public static object InvokeStorageRootMethod(StorageInfo storageRoot, string methodName, params object[] methodArgs)
        { 
            BindingFlags bindingFlags = BindingFlags.Static |
                                        BindingFlags.Instance |
                                        BindingFlags.Public |
                                        BindingFlags.NonPublic |
                                        BindingFlags.InvokeMethod;

            Type storageRootType = typeof(StorageInfo).Assembly.GetType("System.IO.Packaging.StorageRoot",
                true,
                false); 
            object result = storageRootType.InvokeMember(methodName,
                bindingFlags,
                null,
                storageRoot,
                methodArgs);

            return result; 
        }

        /// <summary>
        /// 获取缩略图
        /// </summary>
        /// <param name="file"></param>
        /// <param name="savePath"></param>
        public static void GetImage(string file,string savePath)
        {
            StorageInfo storageRoot = (StorageInfo)InvokeStorageRootMethod(null,
                "Open",
                file,
                FileMode.Open,
                FileAccess.Read,
                FileShare.Read);

            if (storageRoot == null)
            {
                return;
            }

            byte[] preViewData = null;

            StreamInfo[] streams = storageRoot.GetStreams();
            foreach (StreamInfo stream in streams)
            {
                if (stream.Name.ToUpper().Equals("REVITPREVIEW4.0"))
                {
                    preViewData = ParsePreviewInfo(stream);
                }
            }
            InvokeStorageRootMethod(storageRoot, "Close");

            // 获取不到信息返回一个100x100的空图片
            if (preViewData == null || preViewData.Length <= 0)
            {
                using (Bitmap newBitmap = new Bitmap(100, 100))
                {
                    newBitmap.Save(savePath);
                    return;
                }
            }

            // 通过Revit元数据读取到PNG图像的开头
            int startingOffset = GetPngStartingOffset(preViewData);
            if (startingOffset == 0)
            {
                using (Bitmap newBitmap = new Bitmap(100, 100))
                {
                    newBitmap.Save(savePath);
                    return;
                }
            }

            byte[] pngDataBuffer = new byte[preViewData.GetUpperBound(0) - startingOffset + 1];
            // 将PNG图像数据读入字节数组
            using (MemoryStream ms = new MemoryStream(preViewData))
            {
                ms.Position = startingOffset;
                ms.Read(pngDataBuffer, 0, pngDataBuffer.Length);
            }

            byte[] decoderData = null;

            // 如果图像数据有效
            if (pngDataBuffer != null)
            {
                // 使用内存流对PNG图像数据进行解码
                // 并将解码后的数据复制到字节数组中
                using (MemoryStream ms = new MemoryStream(pngDataBuffer))
                {
                    PngBitmapDecoder decoder = new PngBitmapDecoder(ms, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default);
                    decoderData = BitSourceToArray(decoder.Frames[0]);
                }
            }

            // 如果解码的数据有效
            if ((decoderData != null) && (decoderData.Length > 0))
            {
                // 使用另一个内存流创建Bitmap
                // 然后是一张图片Bitmap
                using (MemoryStream ms = new MemoryStream(decoderData))
                {
                    using (Bitmap newBitmap = new Bitmap((ms)))
                    {
                        newBitmap.Save(savePath);
                        return;
                    }
                }
            }

            using (Bitmap newBitmap = new Bitmap(100, 100))
            {
                newBitmap.Save(savePath);
            }
        }

        private static byte[] ParsePreviewInfo(StreamInfo streamInfo)
        {
            byte[] streamData = null;
            try
            {
                using (Stream streamReader = streamInfo.GetStream(FileMode.Open, FileAccess.Read))
                {
                    streamData = new byte[streamReader.Length];
                    streamReader.Read(streamData, 0, streamData.Length);
                    return streamData;
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
            finally
            {
                streamData = null;
            }
        }

        private static byte[] BitSourceToArray(BitmapSource bitmapSource)
        {
            BitmapEncoder encoder = new JpegBitmapEncoder();
            using (MemoryStream ms = new MemoryStream())
            {
                encoder.Frames.Add(BitmapFrame.Create(bitmapSource));
                encoder.Save(ms);
                return ms.ToArray();
            }
        }

        private static int GetPngStartingOffset(byte[] previewData)
        {
            bool markerFound = false;
            int startingOffset = 0;
            int previousValue = 0;
            using (MemoryStream ms = new MemoryStream(previewData))
            {
                for (int i = 0; i < previewData.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;
        } 

总结

以上两种方式都可以导出预览图,根据不同的场景不同需求自由选择。

作者:LIN JIASHUO
来源:在.NET Core上部署WordPress – LINJIASHUO
链接:LINJIASHUO BlOG

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值