internal PdfType0Font(Document document, TrueTypeFont ttf, bool embedSubset, bool closeTTF, bool vertical) : base(document, new PdfDictionary()) { if (vertical) { ttf.EnableVerticalSubstitutions(); } gsubData = ttf.GsubData; cmapLookup = ttf.GetUnicodeCmapLookup(); embedder = new PdfCIDFontType2Embedder(document, Dictionary, ttf, embedSubset, this, vertical); CIDFont = embedder.GetCIDFont(); ReadEncoding(); if (closeTTF) { if (embedSubset) { this.ttf = ttf; //TODO document.registerTrueTypeFontForClosing(ttf); } else { // the TTF is fully loaded and it is safe to close the underlying data source ttf.Dispose(); } } }
/** * Creates a new TrueType font embedder for the given TTF as a PDCIDFontType2. * * @param document parent document * @param dict font dictionary * @param ttf True Type Font * @param parent parent Type 0 font * @ if the TTF could not be read */ public PdfCIDFontType2Embedder(Document document, PdfDictionary dict, TrueTypeFont ttf, bool embedSubset, PdfType0Font parent, bool vertical) : base(document, dict, ttf, embedSubset) { this.document = document; this.dict = dict; this.parent = parent; this.vertical = vertical; // parent Type 0 font dict[PdfName.Subtype] = PdfName.Type0; dict[PdfName.BaseFont] = PdfName.Get(FontDescriptor.FontName); dict[PdfName.Encoding] = vertical ? PdfName.IdentityV : PdfName.IdentityH; // CID = GID // descendant CIDFont cidFont = CreateCIDFont(); PdfArray descendantFonts = new PdfArray(); descendantFonts.Add(document.File.Register(cidFont)); dict[PdfName.DescendantFonts] = descendantFonts; if (!embedSubset) { // build GID -> Unicode map BuildToUnicodeCMap(null); } }
/** * Creates a new TrueType font for embedding. */ public TrueTypeEmbedder(Document document, PdfDictionary dict, TrueTypeFont ttf, bool embedSubset) { this.document = document; this.embedSubset = embedSubset; this.ttf = ttf; fontDescriptor = CreateFontDescriptor(ttf); if (!IsEmbeddingPermitted(ttf)) { throw new IOException("This font does not permit embedding"); } if (!embedSubset) { // full embedding PdfStream stream = new PdfStream(ttf.OriginalData); stream.Header[PdfName.Length] = stream.Header[PdfName.Length1] = PdfInteger.Get(ttf.OriginalDataSize); fontDescriptor.FontFile2 = new FontFile(document, stream); } dict[PdfName.Type] = PdfName.Font; dict[PdfName.BaseFont] = new PdfName(ttf.Name); // choose a Unicode "cmap" cmapLookup = ttf.GetUnicodeCmapLookup(); }
/** * Constructor. * * @param fontDictionary The font dictionary according to the PDF specification. * @param parent The parent font. * @param trueTypeFont The true type font used to create the parent font * @throws IOException */ public CIDFontType2(PdfDirectObject fontDictionary, PdfType0Font parent, TrueTypeFont trueTypeFont) : base(fontDictionary, parent) { FontDescriptor fd = FontDescriptor; if (trueTypeFont != null) { ttf = trueTypeFont; isEmbedded = true; isDamaged = false; } else { bool fontIsDamaged = false; TrueTypeFont ttfFont = null; FontFile stream = null; if (fd != null) { // Acrobat looks in FontFile too, even though it is not in the spec, see PDFBOX-2599 stream = fd.FontFile2 ?? fd.FontFile3 ?? fd.FontFile; } if (stream != null) { try { // embedded OTF or TTF OTFParser otfParser = new OTFParser(true); ttfFont = otfParser.Parse((Bytes.Buffer)stream.BaseDataObject.ExtractBody(true), fd.FontName); if (ttfFont is OpenTypeFont otf && otf.IsPostScript) { // PDFBOX-3344 contains PostScript outlines instead of TrueType fontIsDamaged = true; Debug.WriteLine($"warning: Found CFF/OTF but expected embedded TTF font {fd.FontName}"); } } catch (IOException e) { fontIsDamaged = true; Debug.WriteLine($"warning: Could not read embedded OTF for font {BaseFont} {e}"); } } isEmbedded = ttfFont != null; isDamaged = fontIsDamaged; if (ttfFont == null) { ttfFont = FindFontOrSubstitute(); } ttf = ttfFont; } cmapLookup = ttf.GetUnicodeCmapLookup(false); cid2gid = ReadCIDToGIDMap(); }
/** * Returns true if the fsType in the OS/2 table permits subsetting. */ private bool IsSubsettingPermitted(TrueTypeFont ttf) { if (ttf.OS2Windows != null) { int fsType = ttf.OS2Windows.FsType; if ((fsType & OS2WindowsMetricsTable.FSTYPE_NO_SUBSETTING) == OS2WindowsMetricsTable.FSTYPE_NO_SUBSETTING) { return(false); } } return(true); }
/** * Creates a new TrueType font for embedding. */ private PdfTrueTypeFont(Document document, TrueTypeFont ttf, Encoding encoding, bool closeTTF) : base(document) { PDTrueTypeFontEmbedder embedder = new PDTrueTypeFontEmbedder(document, Dictionary, ttf, encoding); this.encoding = encoding; this.ttf = ttf; FontDescriptor = embedder.FontDescriptor; isEmbedded = true; isDamaged = false; glyphList = GlyphMapping.Default; if (closeTTF) { // the TTF is fully loaded and it is safe to close the underlying data source ttf.Dispose(); } }
/** * Creates a new TrueType font embedder for the given TTF as a PDTrueTypeFont. * * @param document The parent document * @param dict Font dictionary * @param ttfStream TTF stream * @param encoding The PostScript encoding vector to be used for embedding. * @throws IOException if the TTF could not be read */ public PDTrueTypeFontEmbedder(Document document, PdfDictionary dict, TrueTypeFont ttf, Encoding encoding) : base(document, dict, ttf, false) { dict[PdfName.Subtype] = PdfName.TrueType; var glyphList = GlyphMapping.Default; this.fontEncoding = encoding; dict[PdfName.Encoding] = encoding.GetPdfObject(); fontDescriptor.Flags &= ~FlagsEnum.Symbolic; fontDescriptor.Flags |= FlagsEnum.Nonsymbolic; // add the font descriptor dict[PdfName.FontDescriptor] = fontDescriptor.BaseObject; // set the glyph widths SetWidths(dict, glyphList); }
internal PdfTrueTypeFont(PdfDirectObject baseObject) : base(baseObject) { TrueTypeFont ttfFont = null; bool fontIsDamaged = false; if (FontDescriptor != null) { var fd = base.FontDescriptor; var ff2Stream = fd.FontFile2; if (ff2Stream != null) { try { // embedded TTFParser ttfParser = new TTFParser(true); ttfFont = ttfParser.Parse(ff2Stream.BaseDataObject.ExtractBody(true)); } catch (IOException e) { Debug.WriteLine($"warn: Could not read embedded TTF for font {BaseFont} {e}"); fontIsDamaged = true; } } } isEmbedded = ttfFont != null; isDamaged = fontIsDamaged; // substitute if (ttfFont == null) { FontMapping <TrueTypeFont> mapping = FontMappers.Instance.GetTrueTypeFont(BaseFont, FontDescriptor); ttfFont = mapping.Font; if (mapping.IsFallback) { Debug.WriteLine($"warn: Using fallback font '{ttfFont}' for '{BaseFont}'"); } } ttf = ttfFont; ReadEncoding(); }
public void BuildFontFile2(Bytes.Buffer ttfStream) { PdfStream stream = new PdfStream(ttfStream); // as the stream was closed within the PdfStream constructor, we have to recreate it using (var input = (Bytes.Buffer)stream.ExtractBody(true)) { ttf = new TTFParser().ParseEmbedded(input); if (!IsEmbeddingPermitted(ttf)) { throw new IOException("This font does not permit embedding"); } if (fontDescriptor == null) { fontDescriptor = CreateFontDescriptor(ttf); } } stream.Header[PdfName.Length1] = PdfInteger.Get(ttf.OriginalDataSize); fontDescriptor.FontFile2 = new FontFile(document, stream); }
/** * Returns true if the fsType in the OS/2 table permits embedding. */ private bool IsEmbeddingPermitted(TrueTypeFont ttf) { if (ttf.OS2Windows != null) { int fsType = ttf.OS2Windows.FsType; if ((fsType & OS2WindowsMetricsTable.FSTYPE_RESTRICTED) == OS2WindowsMetricsTable.FSTYPE_RESTRICTED) { // restricted License embedding return(false); } else if ((fsType & OS2WindowsMetricsTable.FSTYPE_BITMAP_ONLY) == OS2WindowsMetricsTable.FSTYPE_BITMAP_ONLY) { // bitmap embedding only return(false); } } return(true); }
public FontMapperImpl() { // substitutes for standard 14 fonts substitutes.Add("Courier", new List <string> { "CourierNew", "CourierNewPSMT", "LiberationMono", "NimbusMonL-Regu" }); substitutes.Add("Courier-Bold", new List <string> { "CourierNewPS-BoldMT", "CourierNew-Bold", "LiberationMono-Bold", "NimbusMonL-Bold" }); substitutes.Add("Courier-Oblique", new List <string> { "CourierNewPS-ItalicMT", "CourierNew-Italic", "LiberationMono-Italic", "NimbusMonL-ReguObli" }); substitutes.Add("Courier-BoldOblique", new List <string> { "CourierNewPS-BoldItalicMT", "CourierNew-BoldItalic", "LiberationMono-BoldItalic", "NimbusMonL-BoldObli" }); substitutes.Add("Helvetica", new List <string> { "ArialMT", "Arial", "LiberationSans", "NimbusSanL-Regu" }); substitutes.Add("Helvetica-Bold", new List <string> { "Arial-BoldMT", "Arial-Bold", "LiberationSans-Bold", "NimbusSanL-Bold" }); substitutes.Add("Helvetica-Oblique", new List <string> { "Arial-ItalicMT", "Arial-Italic", "Helvetica-Italic", "LiberationSans-Italic", "NimbusSanL-ReguItal" }); substitutes.Add("Helvetica-BoldOblique", new List <string> { "Arial-BoldItalicMT", "Helvetica-BoldItalic", "LiberationSans-BoldItalic", "NimbusSanL-BoldItal" }); substitutes.Add("Times-Roman", new List <string> { "TimesNewRomanPSMT", "TimesNewRoman", "TimesNewRomanPS", "LiberationSerif", "NimbusRomNo9L-Regu" }); substitutes.Add("Times-Bold", new List <string> { "TimesNewRomanPS-BoldMT", "TimesNewRomanPS-Bold", "TimesNewRoman-Bold", "LiberationSerif-Bold", "NimbusRomNo9L-Medi" }); substitutes.Add("Times-Italic", new List <string> { "TimesNewRomanPS-ItalicMT", "TimesNewRomanPS-Italic", "TimesNewRoman-Italic", "LiberationSerif-Italic", "NimbusRomNo9L-ReguItal" }); substitutes.Add("Times-BoldItalic", new List <string> { "TimesNewRomanPS-BoldItalicMT", "TimesNewRomanPS-BoldItalic", "TimesNewRoman-BoldItalic", "LiberationSerif-BoldItalic", "NimbusRomNo9L-MediItal" }); substitutes.Add("Symbol", new List <string> { "Symbol", "SymbolMT", "StandardSymL" }); substitutes.Add("ZapfDingbats", new List <string> { "ZapfDingbatsITCbyBT-Regular", "ZapfDingbatsITC", "Dingbats", "MS-Gothic" }); // Acrobat also uses alternative names for Standard 14 fonts, which we map to those above // these include names such as "Arial" and "TimesNewRoman" foreach (string baseName in Standard14Fonts.Names) { if (!substitutes.ContainsKey(baseName)) { string mappedName = Standard14Fonts.GetMappedFontName(baseName); substitutes.Add(baseName, CopySubstitutes(mappedName)); } } // ------------------------- try { string ttfName = "fonts.ttf.LiberationSans-Regular"; var ttfStream = typeof(IFontMapper).Assembly.GetManifestResourceStream(ttfName); if (ttfStream == null) { throw new IOException("Error loading resource: " + ttfName); } TTFParser ttfParser = new TTFParser(); lastResortFont = ttfParser.Parse(ttfStream); } catch (IOException e) { throw new Exception("Load LiberationSans", e); } }
/** * Creates a new font descriptor dictionary for the given TTF. */ private FontDescriptor CreateFontDescriptor(TrueTypeFont ttf) { FontDescriptor fd = new FontDescriptor(document, new PdfDictionary()); fd.FontName = ttf.Name; OS2WindowsMetricsTable os2 = ttf.OS2Windows; PostScriptTable post = ttf.PostScript; // Flags var flags = (FlagsEnum)0; flags |= (post.IsFixedPitch > 0 || ttf.HorizontalHeader.NumberOfHMetrics == 1) ? FlagsEnum.FixedPitch : 0; int fsSelection = os2.FsSelection; flags |= ((fsSelection & (ITALIC | OBLIQUE)) != 0) ? FlagsEnum.Italic : 0; switch (os2.FamilyClass) { case OS2WindowsMetricsTable.FAMILY_CLASS_CLAREDON_SERIFS: case OS2WindowsMetricsTable.FAMILY_CLASS_FREEFORM_SERIFS: case OS2WindowsMetricsTable.FAMILY_CLASS_MODERN_SERIFS: case OS2WindowsMetricsTable.FAMILY_CLASS_OLDSTYLE_SERIFS: case OS2WindowsMetricsTable.FAMILY_CLASS_SLAB_SERIFS: flags |= FlagsEnum.Serif; break; case OS2WindowsMetricsTable.FAMILY_CLASS_SCRIPTS: flags |= FlagsEnum.Script; break; default: break; } fd.FontWeight = os2.WeightClass; flags |= FlagsEnum.Symbolic; flags &= ~FlagsEnum.Nonsymbolic; fd.Flags = flags; // ItalicAngle fd.ItalicAngle = post.ItalicAngle; // FontBBox HeaderTable header = ttf.Header; float scaling = 1000f / header.UnitsPerEm; var skRect = new SKRect( header.XMin * scaling, header.YMin * scaling, header.XMax * scaling, header.YMax * scaling ); Rectangle rect = new Rectangle(skRect); fd.FontBBox = rect; // Ascent, Descent HorizontalHeaderTable hHeader = ttf.HorizontalHeader; fd.Ascent = hHeader.Ascender * scaling; fd.Descent = hHeader.Descender * scaling; // CapHeight, XHeight if (os2.Version >= 1.2) { fd.CapHeight = os2.CapHeight * scaling; fd.XHeight = os2.Height * scaling; } else { var capHPath = ttf.GetPath("H"); if (capHPath != null) { fd.CapHeight = (float)Math.Round(capHPath.Bounds.Bottom * scaling); } else { // estimate by summing the typographical +ve ascender and -ve descender fd.CapHeight = os2.TypoAscender + (os2.TypoDescender * scaling); } var xPath = ttf.GetPath("x"); if (xPath != null) { fd.XHeight = (float)Math.Round(xPath.Bounds.Bottom * scaling); } else { // estimate by halving the typographical ascender fd.XHeight = os2.TypoAscender / (2.0f * scaling); } } // StemV - there's no true TTF equivalent of this, so we estimate it fd.StemV = skRect.Width * .13f; return(fd); }
/** * Loads a TTF to be embedded into a document as a simple font. * * <p> * <b>Note:</b> Simple fonts only support 256 characters. For Unicode support, use * {@link PDType0Font#load(Document, Bytes.IInputStream)} instead. * </p> * * @param doc The PDF document that will hold the embedded font. * @param ttf A true type font * @param encoding The PostScript encoding vector to be used for embedding. * @return a PdfTrueTypeFont instance. * @throws IOException If there is an error loading the data. */ public static PdfTrueTypeFont Load(Document doc, TrueTypeFont ttf, Encoding encoding) { return(new PdfTrueTypeFont(doc, ttf, encoding, false)); }
/** * Loads a TTF to be embedded into a document as a vertical Type 0 font. * * @param doc The PDF document that will hold the embedded font. * @param ttf A TrueType font. * @param embedSubset True if the font will be subset before embedding * @return A Type0 font with a CIDFontType2 descendant. * @throws IOException If there is an error reading the font stream. */ public static PdfType0Font LoadVertical(Document doc, TrueTypeFont ttf, bool embedSubset) { return(new PdfType0Font(doc, ttf, embedSubset, false, true)); }