Files
ShrlAlgoToolkit/ShrlAlgoToolkit.RevitAddins/RvFamily/FamilyLibrary/RevitFileUtil.cs
2025-05-05 17:04:06 +08:00

644 lines
23 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.IO.Packaging;
using System.Reflection;
using System.Text;
using System.Windows.Media.Imaging;
using System.Xml;
namespace ShrlAlgoToolkit.RevitAddins.RvFamily.FamilyLibrary
{
/// <summary>
/// 直接读取文件的信息不依赖RevitAPI
/// </summary>
internal static class RevitFileUtil
{
private static string _fileName;
public static Image PreviewImage { get; set; }
public static List<FamilySymbolType> SymbolTypes { get; set; }
public static StringBuilder FileInfo { get; set; }
public static StringBuilder Content { get; set; }
public static StringBuilder TransMissionData { get; set; }
public static string SafeName { get; set; }
public static string Product { get; set; }
public static string RevitVersion { get; set; }
public static string UpdateTime { get; set; }
/// <summary>
/// 图片资源转字节
/// </summary>
/// <param name="bitmapSource"></param>
/// <returns></returns>
public 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();
}
}
public static StringBuilder GetFamilyInfo(List<FamilySymbolType> symbols)
{
StringBuilder sb = new StringBuilder();
foreach (FamilySymbolType symbol in symbols)
{
sb.Append($"族类型:{symbol.Name}{symbol.Value}\r\n");
foreach (Parameter param in symbol.Parameters)
{
sb.Append($" {param.Name}:{param.Value}\r\n");
}
}
return sb;
}
public 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;
}
/// <summary>
/// 获取缩略图
/// </summary>
/// <param name="previewData"></param>
/// <returns></returns>
public static Image GetPreviewAsImage(byte[] previewData)
{
if (previewData == null || previewData.Length <= 0)
{
using (Bitmap newBitmap = new Bitmap(128, 128))
{
return newBitmap.Clone() as Bitmap;
}
}
// read past the Revit metadata to the start of the PNG image
int startingOffset = GetPngStartingOffset(previewData);
if (startingOffset == 0)
{
using (Bitmap newBitmap = new Bitmap(128, 128))
{
return newBitmap.Clone() as Bitmap;
}
}
try
{
byte[] pngDataBuffer = new byte[previewData.GetUpperBound(0) - startingOffset + 1];
// read the PNG image data into a byte array
using (MemoryStream ms = new MemoryStream(previewData))
{
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
using (MemoryStream ms = new MemoryStream(pngDataBuffer))
{
PngBitmapDecoder decoder = new PngBitmapDecoder(ms, BitmapCreateOptions.PreservePixelFormat,
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
using (MemoryStream ms = new MemoryStream(decoderData))
{
using (Bitmap newBitmap = new Bitmap(ms))
{
using (Image newImage = newBitmap)
{
return newImage.Clone() as Image;
}
}
}
}
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
}
using (Bitmap newBitmap = new Bitmap(128, 128))
{
return newBitmap.Clone() as Bitmap;
}
}
public static string ParseDetailInfo(string detailInfo)
{
try
{
detailInfo = detailInfo.Trim();
int index = detailInfo.IndexOf(":");
string detailValue = detailInfo.Substring(detailInfo.IndexOf(":") + 1);
string detailKey = detailInfo.Substring(0, detailInfo.IndexOf(":"));
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))
// {
// WorkSharing = WorkSharingMode.HCLight;
// 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:
// WorkSharing = WorkSharingMode.HCLight;
// 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;
//}
}
public static StringBuilder ParseFileInfo(string unicodeData)
{
StringBuilder s = new StringBuilder();
string[] basicFileInfoParts = unicodeData.Split('\0');
foreach (string basicFileInfoPart in basicFileInfoParts)
{
if (basicFileInfoPart.IndexOf("\r\n", StringComparison.Ordinal) >= 0)
{
string[] detailInfoParts = basicFileInfoPart.Split(new[] { "\r\n" }, new StringSplitOptions());
foreach (string detailPart in detailInfoParts)
{
s.Append(ParseDetailInfo(detailPart) + "\r\n");
}
}
}
return s;
}
/// <summary>
/// 解析参数
/// </summary>
/// <param name="streamInfo"></param>
public static List<FamilySymbolType> ParseParameter(StreamInfo streamInfo)
{
XmlDocument document = new XmlDocument();
string xmlStr;
byte[] streamData;
using (Stream streamReader = streamInfo.GetStream(FileMode.Open, FileAccess.Read))
{
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);
//读取参数信息
XmlElement root = document.DocumentElement;
//节点前缀的命名空间
string nameSpace = root.GetNamespaceOfPrefix("A");
//string nameSpace = root.NamespaceURI;
XmlNamespaceManager nsmgr = new XmlNamespaceManager(document.NameTable);
;
nsmgr.AddNamespace("entry", nameSpace);
//族类型
XmlNodeList xnlist = document.GetElementsByTagName("A:part");
XmlNodeList fileinfo = document.GetElementsByTagName("A:design-file");
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;
List<FamilySymbolType> symbols = new List<FamilySymbolType>();
foreach (XmlNode xn in xnlist)
{
//XmlAttributeCollection attriCol = xn.Attributes;
//foreach (XmlAttribute xmlAttri in attriCol)
//{
// string name = xmlAttri.Name;
// string value = xmlAttri.Value;
//}
FamilySymbolType symbol = new FamilySymbolType();
if (xn.HasChildNodes)
{
foreach (XmlNode child in xn.ChildNodes)
{
Parameter p = new Parameter();
if (child.Name == "title")
{
symbol.Name = child.InnerText;
continue;
}
//族类型节点
p.Name = child.Name;
//族名称
p.Value = child.InnerText;
symbol.Parameters.Add(p);
}
}
symbols.Add(symbol);
}
return symbols;
}
}
public static void ParserRevitFile(string filename)
{
if (filename.EndsWith(".rvt") || filename.EndsWith(".rte") || filename.EndsWith(".rfa") ||
filename.EndsWith(".rft"))
{
_fileName = filename;
//获取Storageroot Object
BindingFlags bindingFlags = BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public |
BindingFlags.NonPublic | BindingFlags.InvokeMethod;
Type 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
};
StorageInfo Storage = (StorageInfo)storageRootType.InvokeMember("Open", bindingFlags, null, null, file);
//if (Storage != null)
//{
// storageRootType.InvokeMember("CloseTrigger", bindingFlags, null, Storage, file);
// //Console.Write($"{filename}文件无法作为结构存储,并打开打开");
//}
//var x = Storage.ThumbnailImage.GetPreviewAsImage();
//读取结构化存储文件
StreamInfo[] streams = Storage.GetStreams();
foreach (StreamInfo streamInfo in streams)
{
string unicodeData;
byte[] streamData = null;
using (Stream streamReader = streamInfo.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);
}
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"))
{
SymbolTypes = ParseParameter(streamInfo);
//Console.WriteLine("族参数:\r\n" + GetFamilyInfo(symbols));
}
}
if (streamInfo.Name.ToUpper().Equals("TRANSMISSIONDATA"))
{
TransMissionData = ParseTransMissionData(unicodeData);
}
if (streamInfo.Name.ToUpper().Equals("REVITPREVIEW4.0"))
{
PreviewImage = ParsePreview(streamInfo);
}
if (streamInfo.Name.ToUpper().Equals("CONTENTS"))
{
Content = ParseContents(unicodeData);
}
}
}
//if (Storage != null)
//{
// try
// {
// storageRootType.InvokeMember("CloseTrigger", bindingFlags, null, Storage, file);
// }
// catch (Exception ex)
// {
// MessageBox.ShowAhead(ex.ViewMessage);
// }
//}
}
public static StringBuilder ParseTransMissionData(string unicodeData)
{
StringBuilder s = new StringBuilder();
string[] basicFileInfoParts = unicodeData.Split('\0');
foreach (string basicFileInfoPart in basicFileInfoParts)
{
if (basicFileInfoPart.IndexOf("\r\n") >= 0)
{
string[] detailInfoParts = basicFileInfoPart.Split(new[] { "\r\n" }, new StringSplitOptions());
foreach (string detailPart in detailInfoParts)
{
s.Append(ParseDetailInfo(detailPart) + "\r\n");
}
}
}
return s;
}
public static void ParseXmlDocument(XmlDocument document)
{
XmlNode rootNode = document.SelectSingleNode("A");
XmlNodeList xmlNodeList = rootNode?.ChildNodes;
if (xmlNodeList == null) return;
foreach (XmlNode xn in xmlNodeList)
{
if (true)
{
}
XmlAttributeCollection xnAttributes = xn.Attributes;
if (xnAttributes != null)
foreach (XmlAttribute attribute in xnAttributes)
{
string name = attribute.Name;
string value = attribute.Value;
}
if (xn.HasChildNodes)
{
}
}
}
/// <summary>
/// 清理无效字符
/// </summary>
/// <param name="oldValue"></param>
/// <returns></returns>
public static string PurgeUnprintableCharacters(string oldValue)
{
StringBuilder sb = new StringBuilder();
char[] oldValueArray = oldValue.ToCharArray();
foreach (char letter in oldValueArray)
{
int decimalValue = letter;
if (decimalValue >= 32 && decimalValue <= 126)
{
sb.Append(letter);
}
}
oldValue = sb.ToString();
sb.Length = 0;
sb.Capacity = 0;
sb = null;
return oldValue;
}
private static StringBuilder ParseContents(string unicodeData)
{
StringBuilder s = new StringBuilder();
string[] basicFileInfoParts = unicodeData.Split('\0');
foreach (string basicFileInfoPart in basicFileInfoParts)
{
if (basicFileInfoPart.IndexOf("\r\n", StringComparison.Ordinal) >= 0)
{
string[] detailInfoParts = basicFileInfoPart.Split(new[] { "\r\n" }, new StringSplitOptions());
foreach (string detailPart in detailInfoParts)
{
s.Append(ParseDetailInfo(detailPart) + "\r\n");
}
}
}
return s;
}
private static StringBuilder ParsePartAtom(string unicodeData)
{
StringBuilder s = new StringBuilder();
string[] basicFileInfoParts = unicodeData.Split('\0');
foreach (string basicFileInfoPart in basicFileInfoParts)
{
if (basicFileInfoPart.IndexOf("\r\n", StringComparison.Ordinal) >= 0)
{
string[] detailInfoParts = basicFileInfoPart.Split(new[] { "\r\n" }, new StringSplitOptions());
foreach (string detailPart in detailInfoParts)
{
s.Append(ParseDetailInfo(detailPart) + "\r\n");
}
}
}
return s;
}
private static Image ParsePreview(StreamInfo stream)
{
byte[] streamData = null;
using (Stream 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);
}
return GetPreviewAsImage(streamData);
}
}
}