最近做到和族库相关的功能需要获取到族文件的预览图,在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