class PDType1FontEmbedder
{
    private final Encoding fontEncoding;
    private final Type1Font type1;
    
    /**
     * 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.
     */
    PDType1FontEmbedder(PDDocument doc, COSDictionary dict, InputStream pfbStream,
                        Encoding encoding) throws IOException
    {
        dict.setItem(COSName.SUBTYPE, COSName.TYPE1);

        // read the pfb
        byte[] pfbBytes = pfbStream.readAllBytes();
        PfbParser pfbParser = new PfbParser(pfbBytes);
        type1 = Type1Font.createWithPFB(pfbBytes);
        
        if (encoding == null)
        {
            fontEncoding = Type1Encoding.fromFontBox(type1.getEncoding());
        }
        else
        {
            fontEncoding = encoding;
        }

        // build font descriptor
        PDFontDescriptor fd = buildFontDescriptor(type1);

        PDStream fontStream = new PDStream(doc, pfbParser.getInputStream(), COSName.FLATE_DECODE);
        fontStream.getCOSObject().setInt("Length", pfbParser.size());
        for (int i = 0; i < pfbParser.getLengths().length; i++)
        {
            fontStream.getCOSObject().setInt("Length" + (i + 1), pfbParser.getLengths()[i]);
        }
        fd.setFontFile(fontStream);

        // set the values
        dict.setItem(COSName.FONT_DESC, fd);
        dict.setName(COSName.BASE_FONT, type1.getName());

        // widths
        List<Integer> widths = new ArrayList<>(256);
        for (int code = 0; code <= 255; code++)
        {
            String name = fontEncoding.getName(code);
            int width = Math.round(type1.getWidth(name));
            widths.add(width);
        }
        
        dict.setInt(COSName.FIRST_CHAR, 0);
        dict.setInt(COSName.LAST_CHAR, 255);
        dict.setItem(COSName.WIDTHS, COSArray.ofCOSIntegers(widths));
        dict.setItem(COSName.ENCODING, encoding);
    }

    /**
     * Returns a PDFontDescriptor for the given PFB.
     * 
     * @throws IOException if the font bounding box isn't available
     */
    static PDFontDescriptor buildFontDescriptor(Type1Font type1) throws IOException
    {
        boolean isSymbolic = type1.getEncoding() instanceof BuiltInEncoding;
        BoundingBox bbox = type1.getFontBBox();
        PDFontDescriptor fd = new PDFontDescriptor();

        fd.setFontName(type1.getName());
        fd.setFontFamily(type1.getFamilyName());
        fd.setNonSymbolic(!isSymbolic);
        fd.setSymbolic(isSymbolic);
        fd.setFontBoundingBox(new PDRectangle(bbox));
        fd.setItalicAngle(type1.getItalicAngle());
        fd.setAscent(bbox.getUpperRightY());
        fd.setDescent(bbox.getLowerLeftY());
        fd.setCapHeight(type1.getBlueValues().get(2).floatValue());
        fd.setStemV(0); // for PDF/A
        return fd;
    }

    /**
     * Returns a PDFontDescriptor for the given AFM. Used only for Standard 14 fonts.
     *
     * @param metrics AFM
     */
    static PDFontDescriptor buildFontDescriptor(FontMetrics metrics)
    {<FILL_FUNCTION_BODY>}
    
    /**
     * Returns the font's encoding.
     */
    public Encoding getFontEncoding()
    {
        return fontEncoding;
    }

    /**
     * Returns the font's glyph list.
     */
    public GlyphList getGlyphList()
    {
        return GlyphList.getAdobeGlyphList();
    }

    /**
     * Returns the Type 1 font.
     */
    public Type1Font getType1Font()
    {
        return type1;
    }
}

        boolean isSymbolic = metrics.getEncodingScheme().equals("FontSpecific");

        PDFontDescriptor fd = new PDFontDescriptor();
        fd.setFontName(metrics.getFontName());
        fd.setFontFamily(metrics.getFamilyName());
        fd.setNonSymbolic(!isSymbolic);
        fd.setSymbolic(isSymbolic);
        fd.setFontBoundingBox(new PDRectangle(metrics.getFontBBox()));
        fd.setItalicAngle(metrics.getItalicAngle());
        fd.setAscent(metrics.getAscender());
        fd.setDescent(metrics.getDescender());
        fd.setCapHeight(metrics.getCapHeight());
        fd.setXHeight(metrics.getXHeight());
        fd.setAverageWidth(metrics.getAverageCharacterWidth());
        fd.setCharacterSet(metrics.getCharacterSet());
        fd.setStemV(0); // for PDF/A
        return fd;
    
<no_super_class>