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 { /// /// 直接读取文件的信息(不依赖RevitAPI) /// internal static class RevitFileUtil { private static string _fileName; public static Image PreviewImage { get; set; } public static List 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; } /// /// 图片资源转字节 /// /// /// 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 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; } /// /// 获取缩略图 /// /// /// 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; } /// /// 解析参数 /// /// public static List 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 symbols = new List(); 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) { } } } /// /// 清理无效字符 /// /// /// 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); } } }