Files
Shrlalgo.RvKits/ShrlAlgoToolkit.RevitAddins/Assists/RevitFileAssist.cs

642 lines
23 KiB
C#
Raw Normal View History

using System.Diagnostics;
2024-09-22 11:05:41 +08:00
using System.Drawing;
using System.IO;
using System.IO.Packaging;
using System.Reflection;
using System.Text;
using System.Windows.Media.Imaging;
using System.Xml;
2025-07-11 09:20:23 +08:00
namespace ShrlAlgoToolkit.RevitAddins.Assists
2024-09-22 11:05:41 +08:00
{
/// <summary>
/// 直接读取文件的信息不依赖RevitAPI
/// </summary>
2025-07-11 09:20:23 +08:00
public class RevitFileAssist
2024-09-22 11:05:41 +08:00
{
2025-07-11 09:20:23 +08:00
public RevitFileAssist(string filePath)
{
if (filePath.EndsWith(".rvt") || filePath.EndsWith(".rte") || filePath.EndsWith(".rfa") ||
filePath.EndsWith(".rft"))
{
ParserRevitFile(filePath);
}
throw new Exception("文件格式不正确!");
}
2024-09-22 11:05:41 +08:00
/// <summary>
/// 图片资源转字节
/// </summary>
/// <param name="bitmapSource"></param>
/// <returns></returns>
2025-07-11 09:20:23 +08:00
private static byte[] BitSourceToArray(BitmapSource bitmapSource)
2024-09-22 11:05:41 +08:00
{
BitmapEncoder encoder = new JpegBitmapEncoder();
2025-07-11 09:20:23 +08:00
using (var ms = new MemoryStream())
2024-09-22 11:05:41 +08:00
{
encoder.Frames.Add(BitmapFrame.Create(bitmapSource));
encoder.Save(ms);
return ms.ToArray();
}
}
2025-07-11 09:20:23 +08:00
private static int GetPngStartingOffset(byte[] previewData)
2024-09-22 11:05:41 +08:00
{
2025-07-11 09:20:23 +08:00
var markerFound = false;
var startingOffset = 0;
var previousValue = 0;
using (var ms = new MemoryStream(previewData))
2024-09-22 11:05:41 +08:00
{
2025-07-11 09:20:23 +08:00
for (var i = 0; i < previewData.Length; i++)
2024-09-22 11:05:41 +08:00
{
2025-07-11 09:20:23 +08:00
var currentValue = ms.ReadByte();
2024-09-22 11:05:41 +08:00
// 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;
}
/// <summary>
/// 获取缩略图
/// </summary>
/// <param name="previewData"></param>
/// <returns></returns>
2025-07-11 09:20:23 +08:00
private static Image GetPreviewAsImage(byte[] previewData)
2024-09-22 11:05:41 +08:00
{
if (previewData == null || previewData.Length <= 0)
{
2025-07-11 09:20:23 +08:00
using (var newBitmap = new Bitmap(128, 128))
2024-09-22 11:05:41 +08:00
{
return newBitmap.Clone() as Bitmap;
}
}
// read past the Revit metadata to the start of the PNG image
2025-07-11 09:20:23 +08:00
var startingOffset = GetPngStartingOffset(previewData);
2024-09-22 11:05:41 +08:00
if (startingOffset == 0)
{
2025-07-11 09:20:23 +08:00
using (var newBitmap = new Bitmap(128, 128))
2024-09-22 11:05:41 +08:00
{
return newBitmap.Clone() as Bitmap;
}
}
try
{
2025-07-11 09:20:23 +08:00
var pngDataBuffer = new byte[previewData.GetUpperBound(0) - startingOffset + 1];
2024-09-22 11:05:41 +08:00
// read the PNG image data into a byte array
2025-07-11 09:20:23 +08:00
using (var ms = new MemoryStream(previewData))
2024-09-22 11:05:41 +08:00
{
ms.Position = startingOffset;
ms.Read(pngDataBuffer, 0, pngDataBuffer.Length);
}
byte[] decoderData = null;
// if the image data is valid
if (pngDataBuffer != null)
{
// use a memory stream to decode the PNG image data
// and copy the decoded data into a byte array
2025-07-11 09:20:23 +08:00
using (var ms = new MemoryStream(pngDataBuffer))
2024-09-22 11:05:41 +08:00
{
2025-07-11 09:20:23 +08:00
var decoder = new PngBitmapDecoder(ms, BitmapCreateOptions.PreservePixelFormat,
2024-09-22 11:05:41 +08:00
BitmapCacheOption.Default);
decoderData = BitSourceToArray(decoder.Frames[0]);
}
}
// if the decoded data is valie
if (decoderData != null && decoderData.Length > 0)
{
// use another memory stream to create a Bitmap
// and then an Image from that Bitmap
2025-07-11 09:20:23 +08:00
using (var ms = new MemoryStream(decoderData))
2024-09-22 11:05:41 +08:00
{
2025-07-11 09:20:23 +08:00
using (var newBitmap = new Bitmap(ms))
2024-09-22 11:05:41 +08:00
{
using (Image newImage = newBitmap)
{
return newImage.Clone() as Image;
}
}
}
}
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
}
2025-07-11 09:20:23 +08:00
using (var newBitmap = new Bitmap(128, 128))
2024-09-22 11:05:41 +08:00
{
return newBitmap.Clone() as Bitmap;
}
}
2025-07-11 09:20:23 +08:00
private static StringBuilder ParseContents(string unicodeData)
{
var s = new StringBuilder();
var basicFileInfoParts = unicodeData.Split('\0');
foreach (var basicFileInfoPart in basicFileInfoParts)
{
if (basicFileInfoPart.IndexOf("\r\n", StringComparison.Ordinal) >= 0)
{
var detailInfoParts = basicFileInfoPart.Split(new[] { "\r\n" }, new StringSplitOptions());
foreach (var detailPart in detailInfoParts)
{
s.Append(ParseDetailInfo(detailPart) + "\r\n");
}
}
}
return s;
}
2024-09-22 11:05:41 +08:00
2025-07-11 09:20:23 +08:00
private static string ParseDetailInfo(string detailInfo)
2024-09-22 11:05:41 +08:00
{
try
{
detailInfo = detailInfo.Trim();
2025-07-11 09:20:23 +08:00
var index = detailInfo.IndexOf(":");
var detailValue = detailInfo.Substring(detailInfo.IndexOf(":") + 1);
var detailKey = detailInfo.Substring(0, detailInfo.IndexOf(":"));
2024-09-22 11:05:41 +08:00
detailKey = detailKey.Trim().ToUpper().Replace(" ", string.Empty);
detailKey = PurgeUnprintableCharacters(detailKey);
detailValue = PurgeUnprintableCharacters(detailValue);
return $"{detailKey}:{detailValue}";
//Console.WriteLine($"{detailKey}:{detailValue}");
}
catch (Exception)
{
return detailInfo;
}
//switch (detailKey)
//{
// case "WORKSHARING":
// if (string.IsNullOrEmpty(detailValue))
// {
2025-05-05 17:04:06 +08:00
// WorkSharing = WorkSharingMode.HCLight;
2024-09-22 11:05:41 +08:00
// return;
// }
// string workSharing = detailValue.Replace(" ", string.Empty).Trim().ToUpper();
// switch (workSharing)
// {
// case "NOTENABLED":
// WorkSharing = WorkSharingMode.NotEnabled;
// break;
// case "LOCAL":
// WorkSharing = WorkSharingMode.Local;
// break;
// case "CENTRAL":
// WorkSharing = WorkSharingMode.Central;
// break;
// default:
2025-05-05 17:04:06 +08:00
// WorkSharing = WorkSharingMode.HCLight;
2024-09-22 11:05:41 +08:00
// break;
// }
// break;
// case "USERNAME":
// UserName = detailValue.Trim();
// break;
// case "CENTRALFILEPATH":
// CentralFilePath = detailValue.Trim();
// break;
// case "REVITBUILD":
// RevitBuild = detailValue.Trim();
// break;
// case "LASTSAVEPATH":
// LastSavedpath = detailValue.Trim();
// break;
// case "OPENWORKSETDEFAULT":
// OpenWorksetDefault = Convert.ToInt32(detailValue.Trim());
// break;
// default:
// Console.WriteLine($"{detailKey}:{detailValue}");
// //Debug.Assert(false, string.Format("{0} was not found in the case tests.", detailKey));
// break;
//}
}
2025-07-11 09:20:23 +08:00
private static StringBuilder ParseFileInfo(string unicodeData)
2024-09-22 11:05:41 +08:00
{
2025-07-11 09:20:23 +08:00
var s = new StringBuilder();
2024-09-22 11:05:41 +08:00
2025-07-11 09:20:23 +08:00
var basicFileInfoParts = unicodeData.Split('\0');
2024-09-22 11:05:41 +08:00
2025-07-11 09:20:23 +08:00
foreach (var basicFileInfoPart in basicFileInfoParts)
2024-09-22 11:05:41 +08:00
{
if (basicFileInfoPart.IndexOf("\r\n", StringComparison.Ordinal) >= 0)
{
2025-07-11 09:20:23 +08:00
var detailInfoParts = basicFileInfoPart.Split(new[] { "\r\n" }, new StringSplitOptions());
foreach (var detailPart in detailInfoParts)
2024-09-22 11:05:41 +08:00
{
s.Append(ParseDetailInfo(detailPart) + "\r\n");
}
}
}
return s;
}
/// <summary>
/// 解析参数
/// </summary>
/// <param name="streamInfo"></param>
2025-07-11 09:20:23 +08:00
private List<FamilyTypeDefinition> ParseParameterDefinition(StreamInfo streamInfo)
2024-09-22 11:05:41 +08:00
{
2025-07-11 09:20:23 +08:00
var document = new XmlDocument();
2024-09-22 11:05:41 +08:00
string xmlStr;
byte[] streamData;
2025-07-11 09:20:23 +08:00
using (var streamReader = streamInfo.GetStream(FileMode.Open, FileAccess.Read))
2024-09-22 11:05:41 +08:00
{
streamData = new byte[streamReader.Length];
streamReader.Read(streamData, 0, streamData.Length);
xmlStr = Encoding.UTF8.GetString(streamData);
document.LoadXml(xmlStr);
//string xmldocpath = Path.GetFileNameWithoutExtension(FileName) + ".xml";
//document.Save(xmldocpath);
//读取参数信息
2025-07-11 09:20:23 +08:00
var root = document.DocumentElement;
2024-09-22 11:05:41 +08:00
//节点前缀的命名空间
2025-08-20 12:10:35 +08:00
var nameSpace = root.GetNamespaceOfui:InputAssist.Prefix("A");
2024-09-22 11:05:41 +08:00
//string nameSpace = root.NamespaceURI;
2025-07-11 09:20:23 +08:00
var nsmgr = new XmlNamespaceManager(document.NameTable);
2024-09-22 11:05:41 +08:00
;
nsmgr.AddNamespace("entry", nameSpace);
//族类型
2025-07-11 09:20:23 +08:00
var xnlist = document.GetElementsByTagName("A:part");
2024-09-22 11:05:41 +08:00
2025-07-11 09:20:23 +08:00
var fileinfo = document.GetElementsByTagName("A:design-file");
2024-09-22 11:05:41 +08:00
foreach (XmlNode xn in fileinfo)
{
if (xn.HasChildNodes)
{
foreach (XmlNode child in xn.ChildNodes)
{
if (child.Name == "A:title")
{
SafeName = child.InnerText;
}
if (child.Name == "A:product")
{
Product = child.InnerText;
}
if (child.Name == "A:product-version")
{
RevitVersion = child.InnerText;
}
if (child.Name == "A:product-updated")
{
UpdateTime = child.InnerText;
}
}
}
}
//XmlNode rootnode = document.SelectSingleNode("/entry/A: family/A:part", nsmgr);
//XmlNodeList xnlist = rootnode.ChildNodes;
2025-07-11 09:20:23 +08:00
var symbols = new List<FamilyTypeDefinition>();
2024-09-22 11:05:41 +08:00
foreach (XmlNode xn in xnlist)
{
//XmlAttributeCollection attriCol = xn.Attributes;
//foreach (XmlAttribute xmlAttri in attriCol)
//{
// string name = xmlAttri.Name;
// string value = xmlAttri.Value;
//}
2025-07-11 09:20:23 +08:00
var symbol = new FamilyTypeDefinition();
2024-09-22 11:05:41 +08:00
if (xn.HasChildNodes)
{
foreach (XmlNode child in xn.ChildNodes)
{
2025-07-11 09:20:23 +08:00
var p = new ParameterDefinition();
2024-09-22 11:05:41 +08:00
if (child.Name == "title")
{
symbol.Name = child.InnerText;
continue;
}
//族类型节点
p.Name = child.Name;
//族名称
p.Value = child.InnerText;
2025-07-11 09:20:23 +08:00
symbol.ParameterDefinitions.Add(p);
2024-09-22 11:05:41 +08:00
}
}
symbols.Add(symbol);
}
return symbols;
}
}
2025-07-11 09:20:23 +08:00
private static StringBuilder ParsePartAtom(string unicodeData)
2024-09-22 11:05:41 +08:00
{
2025-07-11 09:20:23 +08:00
var s = new StringBuilder();
var basicFileInfoParts = unicodeData.Split('\0');
2024-09-22 11:05:41 +08:00
2025-07-11 09:20:23 +08:00
foreach (var basicFileInfoPart in basicFileInfoParts)
{
if (basicFileInfoPart.IndexOf("\r\n", StringComparison.Ordinal) >= 0)
2024-09-22 11:05:41 +08:00
{
2025-07-11 09:20:23 +08:00
var detailInfoParts = basicFileInfoPart.Split(new[] { "\r\n" }, new StringSplitOptions());
foreach (var detailPart in detailInfoParts)
2024-09-22 11:05:41 +08:00
{
2025-07-11 09:20:23 +08:00
s.Append(ParseDetailInfo(detailPart) + "\r\n");
2024-09-22 11:05:41 +08:00
}
}
}
2025-07-11 09:20:23 +08:00
return s;
2024-09-22 11:05:41 +08:00
}
2025-07-11 09:20:23 +08:00
/// <summary>
/// 解析预览图像
/// </summary>
/// <param name="stream"></param>
/// <returns></returns>
private static Image ParsePreviewImage(StreamInfo stream)
{
byte[] streamData = null;
using (var streamReader = stream.GetStream(FileMode.Open, FileAccess.Read))
{
streamData = new byte[streamReader.Length];
streamReader.Read(streamData, 0, streamData.Length);
//unicodeData = Encoding.Unicode.GetString(streamData);
//unicodeData = Encoding.UTF8.GetString(streamData);
}
2024-09-22 11:05:41 +08:00
2025-07-11 09:20:23 +08:00
return GetPreviewAsImage(streamData);
}
/// <summary>
/// 解析传输数据
/// </summary>
/// <param name="unicodeData"></param>
/// <returns></returns>
private static StringBuilder ParseTransMissionData(string unicodeData)
2024-09-22 11:05:41 +08:00
{
2025-07-11 09:20:23 +08:00
var s = new StringBuilder();
2024-09-22 11:05:41 +08:00
2025-07-11 09:20:23 +08:00
var basicFileInfoParts = unicodeData.Split('\0');
2024-09-22 11:05:41 +08:00
2025-07-11 09:20:23 +08:00
foreach (var basicFileInfoPart in basicFileInfoParts)
2024-09-22 11:05:41 +08:00
{
if (basicFileInfoPart.IndexOf("\r\n") >= 0)
{
2025-07-11 09:20:23 +08:00
var detailInfoParts = basicFileInfoPart.Split(new[] { "\r\n" }, new StringSplitOptions());
foreach (var detailPart in detailInfoParts)
2024-09-22 11:05:41 +08:00
{
s.Append(ParseDetailInfo(detailPart) + "\r\n");
}
}
}
return s;
}
2025-07-11 09:20:23 +08:00
//public static StringBuilder GetFamilyInfo(List<FamilyTypeDefinition> symbols)
//{
// var sb = new StringBuilder();
// foreach (var symbol in symbols)
// {
// sb.Append($"族类型:{symbol.Name}{symbol.Value}\r\n");
// foreach (var param in symbol.ParameterDefinitions)
// {
// sb.Append($" {param.Name}:{param.Value}\r\n");
// }
// }
// return sb;
//}
/// <summary>
/// 解析Revit文件信息
/// </summary>
/// <param name="filename"></param>
private void ParserRevitFile(string filename)
2024-09-22 11:05:41 +08:00
{
2025-07-11 09:20:23 +08:00
//获取Storageroot Object
var bindingFlags = BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public |
BindingFlags.NonPublic | BindingFlags.InvokeMethod;
var storageRootType = typeof(StorageInfo).Assembly.GetType("System.IO.Packaging.StorageRoot", true, false);
//Type storageRootType = typeof(StorageInfo).Assembly.GetType("System.IO.Packaging", true, false);
object[] file =
{
filename,
FileMode.Open,
FileAccess.Read,
FileShare.Read
};
var Storage = (StorageInfo)storageRootType.InvokeMember("Open", bindingFlags, null, null, file);
//if (Storage != null)
//{
// storageRootType.InvokeMember("CloseTrigger", bindingFlags, null, Storage, file);
// //Console.Write($"{filePath}文件无法作为结构存储,并打开打开");
//}
//var x = Storage.ThumbnailImage.GetPreviewAsImage();
//读取结构化存储文件
var streams = Storage.GetStreams();
foreach (var streamInfo in streams)
2024-09-22 11:05:41 +08:00
{
2025-07-11 09:20:23 +08:00
string unicodeData;
byte[] streamData = null;
using (var streamReader = streamInfo.GetStream(FileMode.Open, FileAccess.Read))
2024-09-22 11:05:41 +08:00
{
2025-07-11 09:20:23 +08:00
streamData = new byte[streamReader.Length];
streamReader.Read(streamData, 0, streamData.Length);
unicodeData = Encoding.Unicode.GetString(streamData);
//unicodeData = Encoding.UTF8.GetString(streamData);
2024-09-22 11:05:41 +08:00
}
2025-07-11 09:20:23 +08:00
if (streamInfo.Name.ToUpper().Equals("BASICFILEINFO"))
{
FileInfo = ParseFileInfo(unicodeData);
}
if (streamInfo.Name.ToUpper().Equals("PARTATOM"))
{
//Console.WriteLine("部分原子:\r\n" + ParsePartAtom(unicodeData));
if (filename.EndsWith(".rfa"))
2024-09-22 11:05:41 +08:00
{
2025-07-11 09:20:23 +08:00
SymbolTypes = ParseParameterDefinition(streamInfo);
//Console.WriteLine("族参数:\r\n" + GetFamilyInfo(symbols));
2024-09-22 11:05:41 +08:00
}
2025-07-11 09:20:23 +08:00
}
2024-09-22 11:05:41 +08:00
2025-07-11 09:20:23 +08:00
if (streamInfo.Name.ToUpper().Equals("TRANSMISSIONDATA"))
2024-09-22 11:05:41 +08:00
{
2025-07-11 09:20:23 +08:00
TransMissionData = ParseTransMissionData(unicodeData);
}
if (streamInfo.Name.ToUpper().Equals("REVITPREVIEW4.0"))
{
PreviewImage = ParsePreviewImage(streamInfo);
}
if (streamInfo.Name.ToUpper().Equals("CONTENTS"))
{
Content = ParseContents(unicodeData);
2024-09-22 11:05:41 +08:00
}
}
2025-07-11 09:20:23 +08:00
//if (Storage != null)
//{
// try
// {
// storageRootType.InvokeMember("CloseTrigger", bindingFlags, null, Storage, file);
// }
// catch (Exception ex)
// {
// MessageBox.ShowAhead(ex.ViewMessage);
// }
//}
2024-09-22 11:05:41 +08:00
}
/// <summary>
/// 清理无效字符
/// </summary>
/// <param name="oldValue"></param>
/// <returns></returns>
public static string PurgeUnprintableCharacters(string oldValue)
{
2025-07-11 09:20:23 +08:00
var sb = new StringBuilder();
var oldValueArray = oldValue.ToCharArray();
foreach (var letter in oldValueArray)
2024-09-22 11:05:41 +08:00
{
int decimalValue = letter;
if (decimalValue >= 32 && decimalValue <= 126)
{
sb.Append(letter);
}
}
oldValue = sb.ToString();
sb.Length = 0;
sb.Capacity = 0;
sb = null;
return oldValue;
}
2025-07-11 09:20:23 +08:00
public StringBuilder Content { get; private set; }
2024-09-22 11:05:41 +08:00
2025-07-11 09:20:23 +08:00
public StringBuilder FileInfo { get; private set; }
public Image PreviewImage { get; private set; }
public string Product { get; private set; }
public string RevitVersion { get; private set; }
public string SafeName { get; private set; }
public List<FamilyTypeDefinition> SymbolTypes { get; private set; }
public StringBuilder TransMissionData { get; private set; }
public string UpdateTime { get; private set; }
2024-09-22 11:05:41 +08:00
2025-07-11 09:20:23 +08:00
public class FamilyTypeDefinition
2024-09-22 11:05:41 +08:00
{
2025-07-11 09:20:23 +08:00
public string Name { get; set; }
public List<ParameterDefinition> ParameterDefinitions { get; set; } = new();
public string Value { get; set; }
2024-09-22 11:05:41 +08:00
}
2025-07-11 09:20:23 +08:00
public class ParameterDefinition
2024-09-22 11:05:41 +08:00
{
2025-07-11 09:20:23 +08:00
public string Name { get; set; }
public string TypeOfParameterDefinition { get; set; }
public string Value { get; set; }
2024-09-22 11:05:41 +08:00
}
}
}