UNPKG

@itwin/core-backend

Version:
135 lines 5.17 kB
/*--------------------------------------------------------------------------------------------- * Copyright (c) Bentley Systems, Incorporated. All rights reserved. * See LICENSE.md in the project root for license terms and full copyright notice. *--------------------------------------------------------------------------------------------*/ import * as fs from "fs"; import { FontType } from "@itwin/core-common"; import { _faceProps, _getData, _implementationProhibited, _key } from "./Symbols"; import { compareNumbersOrUndefined } from "@itwin/core-bentley"; import { IModelNative } from "./NativePlatform"; class FontFileImpl { [_implementationProhibited] = undefined; faces; get isEmbeddable() { return true; } [_key]; [_faceProps]; constructor(faces) { this.faces = faces.map((face) => { return { familyName: face.familyName, isBold: face.faceName.startsWith("bold"), isItalic: face.faceName.endsWith("italic"), }; }); this[_faceProps] = faces; // Sort the face props in canonical order so we can compare FontFiles for equivalent contents. this[_faceProps].sort((a, b) => a.familyName.localeCompare(b.familyName) || a.faceName.localeCompare(b.faceName) || compareNumbersOrUndefined(a.subId, b.subId)); // Stringify the face props so that the key properties (and no other properties) appear in a canonical order. for trivial comparisons. this[_key] = JSON.stringify(this[_faceProps], ["familyName", "faceName", "type", "subId"]); } } /** Points to an OpenType font file on disk. */ class TrueTypeFontFile extends FontFileImpl { #fileName; #embeddable; constructor(fileName, embeddable, faces) { super(faces); this.#fileName = fileName; this.#embeddable = embeddable; } get type() { return FontType.TrueType; } get isEmbeddable() { return this.#embeddable; } [_getData]() { return fs.readFileSync(this.#fileName); } } /** Holds the binary representation of a SHX or RSC font in memory. */ export class CadFontFile extends FontFileImpl { #data; #type; constructor(data, type, faces) { super(faces); this.#data = data; this.#type = type; } get type() { return this.#type; } [_getData]() { return this.#data; } } /** Points to a font file in any format embedded in an iModel. */ export class EmbeddedFontFile extends FontFileImpl { // The value of the Id column for the row in the be_Prop table that embeds this font's data. #db; #id; #type; constructor(db, id, type, faces) { super(faces); this.#db = db; this.#id = id; this.#type = type; } get type() { return this.#type; } [_getData]() { const data = this.#db.queryFilePropertyBlob({ namespace: "dgn_Font", name: "EmbeddedFaceData", id: this.#id, }); if (!data) { throw new Error("Embedded font not found"); } return data; } } export function shxFontFileFromBlob(args) { if (args.familyName.length === 0) { throw new Error("Font family name cannot be empty"); } // An SHX file with fewer than 40 bytes isn't valid. const minShxSize = 40; const shxHeaders = [ "AutoCAD-86 unifont 1.0", "AutoCAD-86 shapes 1.0", "AutoCAD-86 shapes 1.1", ].map((shxHeader) => Array.from(shxHeader)) .map((chars) => new Uint8Array(chars.map((ch) => ch.charCodeAt(0)))); // See https://github.com/iTwin/imodel-native/blob/91f509c2175dc49ce1efcf5a906c9a9aa193451d/iModelCore/iModelPlatform/DgnCore/ShxFont.cpp#L44 function validateShx(blob) { if (blob.length >= minShxSize) { for (const header of shxHeaders) { if (header.every((char, index) => char === blob[index])) { return; } } } throw new Error("Failed to read font file"); } validateShx(args.blob); return new CadFontFile(args.blob, FontType.Shx, [{ faceName: "regular", familyName: args.familyName, type: FontType.Shx, }]); } export function rscFontFileFromBlob(args) { if (args.familyName.length === 0) { throw new Error("Font family name cannot be empty"); } if (!IModelNative.platform.isRscFontData(args.blob)) { throw new Error("Failed to read font file"); } return new CadFontFile(args.blob, FontType.Rsc, [{ faceName: "regular", familyName: args.familyName, type: FontType.Rsc, encoding: args.encoding, }]); } export function trueTypeFontFileFromFileName(fileName) { const metadata = IModelNative.platform.getTrueTypeFontMetadata(fileName); if (metadata.faces.length === 0) { // The input was almost certainly not a TrueType font file. throw new Error("Failed to read font file"); } return new TrueTypeFontFile(fileName, metadata.embeddable, metadata.faces); } //# sourceMappingURL=FontFileImpl.js.map