Пример #1
0
        /**
         * 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();
        }
Пример #2
0
        /**
         * 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();
        }
Пример #3
0
        /**
         * This will load a PFB to be embedded into a document.
         *
         * @param doc The PDF document that will hold the embedded font.
         * @param dict The Font dictionary to write to.
         * @param pfbStream The pfb input.
         * @throws IOException If there is an error loading the data.
         */
        public PdfType1FontEmbedder(Document doc, PdfDictionary dict, Bytes.IInputStream pfbStream, Encoding encoding)
        {
            dict[PdfName.Subtype] = PdfName.Type1;

            // read the pfb
            byte[]    pfbBytes  = pfbStream.ToByteArray();
            PfbParser pfbParser = new PfbParser(pfbBytes);

            type1 = Type1Font.CreateWithPFB(pfbBytes);

            if (encoding == null)
            {
                fontEncoding = Type1Encoding.FromFontBox(type1.Encoding);
            }
            else
            {
                fontEncoding = encoding;
            }

            // build font descriptor
            FontDescriptor fd = BuildFontDescriptor(type1);

            PdfStream fontStream = new PdfStream(pfbParser.GetInputStream());

            fontStream.Header[PdfName.Length] = PdfInteger.Get(pfbParser.Size);
            for (int i = 0; i < pfbParser.Lengths.Length; i++)
            {
                fontStream.Header[new PdfName("Length" + (i + 1))] = PdfInteger.Get(pfbParser.Lengths[i]);
            }
            fd.FontFile = new FontFile(doc, fontStream);

            // set the values
            dict[PdfName.FontDescriptor] = fd.BaseObject;
            dict[PdfName.BaseFont]       = PdfName.Get(type1.Name);

            // widths
            List <int> widths = new List <int>(256);

            for (int code = 0; code <= 255; code++)
            {
                string name  = fontEncoding.GetName(code);
                int    width = (int)Math.Round(type1.GetWidth(name));
                widths.Add(width);
            }

            dict[PdfName.FirstChar] = PdfInteger.Get(0);
            dict[PdfName.LastChar]  = PdfInteger.Get(255);
            dict[PdfName.Widths]    = new PdfArray(widths.Select(p => PdfInteger.Get(p)));
            dict[PdfName.Encoding]  = encoding.GetPdfObject();
        }
Пример #4
0
        /**
         * Returns a FontDescriptor for the given PFB.
         */
        public static FontDescriptor BuildFontDescriptor(Type1Font type1)
        {
            bool isSymbolic = type1.Encoding is BuiltInEncoding;

            FontDescriptor fd = new FontDescriptor();

            fd.FontName    = type1.Name;
            fd.FontFamily  = type1.FamilyName;
            fd.NonSymbolic = !isSymbolic;
            fd.Symbolic    = isSymbolic;
            fd.FontBBox    = new Rectangle(type1.FontBBox);
            fd.ItalicAngle = type1.ItalicAngle;
            fd.Ascent      = type1.FontBBox.Top;
            fd.Descent     = type1.FontBBox.Bottom;
            fd.CapHeight   = type1.BlueValues[2];
            fd.StemV       = 0; // for PDF/A
            return(fd);
        }
Пример #5
0
        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);
        }
Пример #6
0
        /**
         * Returns a FontDescriptor for the given AFM. Used only for Standard 14 fonts.
         *
         * @param metrics AFM
         */
        public static FontDescriptor BuildFontDescriptor(FontMetrics metrics)
        {
            bool isSymbolic = metrics.EncodingScheme.Equals("FontSpecific", StringComparison.Ordinal);

            FontDescriptor fd = new FontDescriptor();

            fd.FontName    = metrics.FontName;
            fd.FontFamily  = metrics.FamilyName;
            fd.NonSymbolic = !isSymbolic;
            fd.Symbolic    = isSymbolic;
            fd.FontBBox    = new Rectangle(metrics.FontBBox);
            fd.ItalicAngle = metrics.ItalicAngle;
            fd.Ascent      = metrics.Ascender;
            fd.Descent     = metrics.Descender;
            fd.CapHeight   = metrics.CapHeight;
            fd.XHeight     = metrics.XHeight;
            fd.AvgWidth    = metrics.GetAverageCharacterWidth();
            fd.CharSet     = metrics.CharacterSet;
            fd.StemV       = 0; // for PDF/A
            return(fd);
        }
Пример #7
0
        /**
         * Constructor.
         *
         * @param fontDictionary The font dictionary according to the PDF specification.
         * @param parent The parent font.
         */
        public CIDFontType0(PdfDirectObject fontDictionary, PdfType0Font parent)
            : base(fontDictionary, parent)
        {
            FontDescriptor fd       = FontDescriptor;
            FontFile       fontFile = null;

            byte[] bytes = null;
            if (fd != null)
            {
                fontFile = fd.FontFile3 ?? fd.FontFile;
                if (fontFile != null)
                {
                    bytes = fontFile.BaseDataObject.ExtractBody(true).GetBuffer();
                }
            }

            bool    fontIsDamaged = false;
            CFFFont cffFont       = null;

            if (bytes != null && bytes.Length > 0 && (bytes[0] & 0xff) == '%')
            {
                // PDFBOX-2642 contains a corrupt PFB font instead of a CFF
                Debug.WriteLine("warn: Found PFB but expected embedded CFF font " + fd.FontName);

                try
                {
                    t1Font = PdfType1Font.LoadType1Font(fontFile);
                }
                catch (DamagedFontException e)
                {
                    Debug.WriteLine($"warn: Can't read damaged embedded Type1 font {fd.FontName} {e}");
                    fontIsDamaged = true;
                }
                catch (IOException e)
                {
                    Debug.WriteLine($"error: Can't read the embedded Type1 font {fd.FontName} {e}");
                    fontIsDamaged = true;
                }
            }
            else if (bytes != null)
            {
                CFFParser cffParser = new CFFParser();
                try
                {
                    cffFont = cffParser.Parse(bytes, new FF3ByteSource(fd, bytes))[0];
                }
                catch (IOException e)
                {
                    Debug.WriteLine("error: Can't read the embedded CFF font " + fd.FontName, e);
                    fontIsDamaged = true;
                }
            }

            if (cffFont != null)
            {
                // embedded
                if (cffFont is CFFCIDFont)
                {
                    cidFont = (CFFCIDFont)cffFont;
                    t1Font  = null;
                }
                else
                {
                    cidFont = null;
                    t1Font  = cffFont;
                }
                cid2gid    = ReadCIDToGIDMap();
                isEmbedded = true;
                isDamaged  = false;
            }
            else if (t1Font != null)
            {
                if (t1Font is Type1Font type1Font)
                {
                    cidFont = null;
                }
                cid2gid    = ReadCIDToGIDMap();
                isEmbedded = true;
                isDamaged  = false;
            }
            else
            {
                // find font or substitute
                CIDFontMapping mapping = FontMappers.Instance.GetCIDFont(BaseFont, FontDescriptor, CIDSystemInfo);
                BaseFont       font;
                if (mapping.IsCIDFont)
                {
                    cffFont = mapping.Font.CFF.Font;
                    if (cffFont is CFFCIDFont)
                    {
                        cidFont = (CFFCIDFont)cffFont;
                        t1Font  = null;
                        font    = cidFont;
                    }
                    else
                    {
                        // PDFBOX-3515: OpenType fonts are loaded as CFFType1Font
                        CFFType1Font f = (CFFType1Font)cffFont;
                        cidFont = null;
                        t1Font  = f;
                        font    = f;
                    }
                }
                else
                {
                    cidFont = null;
                    t1Font  = mapping.TrueTypeFont;
                    font    = t1Font;
                }

                if (mapping.IsFallback)
                {
                    Debug.WriteLine($"warning: Using fallback {font.Name} for CID-keyed font {BaseFont}");
                }
                isEmbedded = false;
                isDamaged  = fontIsDamaged;
            }
            fontMatrixTransform = FontMatrix;
            fontMatrixTransform = fontMatrixTransform.PostConcat(SKMatrix.CreateScale(1000, 1000));
        }
Пример #8
0
        /**
         * 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);
        }