UNPKG

@parametricos/bcf-js

Version:

BCF.js is a BIM Collaboration Format (BCF) reader & parser.

191 lines 7.36 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Markup = void 0; const fflate_1 = require("fflate"); const fast_xml_parser_1 = require("fast-xml-parser"); class BcfReader { version; bcf_archive; project; markups = []; helpers; constructor(version, helpers) { this.version = version; this.helpers = helpers; } read = async (src) => { try { const markups = []; // Convert different input types to Uint8Array for fflate let data; if (src instanceof ArrayBuffer) { data = new Uint8Array(src); } else if (src instanceof Uint8Array) { data = src; } else if (src instanceof Blob) { const arrayBuffer = await src.arrayBuffer(); data = new Uint8Array(arrayBuffer); } else if (typeof src === "string") { // If it's a string, assume it's a base64 or URL - convert appropriately // For now, we'll throw an error as string URLs need different handling throw new Error("String URLs not supported in fflate version. Please provide ArrayBuffer, Uint8Array, or Blob."); } else { throw new Error("Unsupported input type for fflate"); } this.bcf_archive = (0, fflate_1.unzipSync)(data); let projectId = ""; let projectName = ""; let projectVersion = ""; let extension_schema = undefined; for (const [name, fileData] of Object.entries(this.bcf_archive)) { const data = fileData; if (name.endsWith(".bcf")) { markups.push(name); } else if (name.endsWith(".version")) { const text = new TextDecoder().decode(data); const parsedEntry = new fast_xml_parser_1.XMLParser(this.helpers.XmlParserOptions).parse(text); projectVersion = parsedEntry.Version.DetailedVersion; } else if (name.endsWith(".bcfp")) { const text = new TextDecoder().decode(data); const parsedEntry = new fast_xml_parser_1.XMLParser(this.helpers.XmlParserOptions).parse(text); if (!parsedEntry.ProjectExtension || !parsedEntry.ProjectExtension.Project) continue; //NOTE: Throw an error here? projectId = parsedEntry.ProjectExtension.Project["@_ProjectId"] || ""; //NOTE: Throw an error here? projectName = parsedEntry.ProjectExtension.Project.Name || ""; } else if (name.endsWith("extensions.xsd")) { const text = new TextDecoder().decode(data); const parsedEntry = new fast_xml_parser_1.XMLParser(this.helpers.XmlParserOptions).parse(text); extension_schema = this.helpers.XmlToJsonNotation(parsedEntry); } } const purged_markups = []; for (let i = 0; i < markups.length; i++) { const markupName = markups[i]; const markup = new Markup(this, markupName); await markup.read(); this.markups.push(markup); const purged_markup = { header: markup.header, topic: markup.topic, project: this.project, viewpoints: markup.viewpoints, }; purged_markups.push(purged_markup); } this.project = { project_id: projectId, name: projectName, version: projectVersion, markups: undefined, reader: this, extension_schema: extension_schema, }; this.project.markups = purged_markups.map((mkp) => { return { ...mkp, project: this.project }; }); } catch (e) { console.log("Error in loading BCF archive. The error below was thrown."); console.error(e); } }; getEntry = (name) => { return this.bcf_archive?.[name]; }; } exports.default = BcfReader; class Markup { reader; markup_name; header; topic; viewpoints = []; constructor(reader, markupName) { this.reader = reader; this.markup_name = markupName; } read = async () => { await this.parseMarkup(); await this.parseViewpoints(); }; parseMarkup = async () => { const fileData = this.reader.getEntry(this.markup_name); if (!fileData) throw new Error("Missing markup file"); const text = new TextDecoder().decode(fileData); const markup = this.reader.helpers.GetMarkup(text); this.topic = markup.topic; this.header = markup.header; }; parseViewpoints = async () => { if (!this.topic) return; if (this.topic.viewpoints) { const topic_viewpoints = this.topic.viewpoints; for (let i = 0; i < topic_viewpoints.length; i++) { const entry = topic_viewpoints[i]; const key = this.topic.guid + "/" + entry.viewpoint; const fileData = this.reader.getEntry(key); if (!fileData) throw new Error("Missing Visualization Info"); const text = new TextDecoder().decode(fileData); const viewpoint = this.reader.helpers.GetViewpoint(text); viewpoint.snapshot = entry.snapshot; viewpoint.getSnapshot = async () => { if (entry.snapshot) return await this.getSnapshot(entry.snapshot); }; this.viewpoints.push(viewpoint); } } }; /** * Parses the png snapshot. * * @returns {string} The image in base64String format. * * @deprecated This function is deprecated and will be removed in the next version.<br> * Please use viewpoint.getSnapshot() instead.<br> * */ getViewpointSnapshot = async (viewpoint) => { if (!viewpoint || !this.topic) return; const fileData = this.reader.getEntry(`${this.topic.guid}/${viewpoint.snapshot}`); if (fileData) { return uint8ToBase64(fileData); } }; /** * Parses the png snapshot. * * @returns {string} The image in base64String format. */ getSnapshot = async (guid) => { if (!guid || !this.topic) return; const fileData = this.reader.getEntry(`${this.topic.guid}/${guid}`); if (fileData) { return uint8ToBase64(fileData); } }; } exports.Markup = Markup; function uint8ToBase64(bytes) { let binary = ""; const chunkSize = 0x8000; // 32k chunks for (let i = 0; i < bytes.length; i += chunkSize) { const chunk = bytes.subarray(i, i + chunkSize); binary += String.fromCharCode.apply(null, chunk); } return btoa(binary); } //# sourceMappingURL=BcfReader.js.map