Apache FOP-有没有办法以编程方式嵌入字体?

时间:2019-02-25 08:00:54

标签: java web apache-fop

使用Apache FOP创建PDF时,可以在配置文件中嵌入字体。当应用程序是Web应用程序并且需要在WAR文件(因此被视为资源)中嵌入字体时,就会出现问题。

使用特定容器的文件夹结构来确定战争的确切位置是不可接受的(在配置xml文件中,我们将标签设置为./时,它会被设置为运行容器的基本文件夹,例如{{ 1}})。

所以问题是:有人知道以编程方式嵌入字体的方法吗?

2 个答案:

答案 0 :(得分:1)

经过大量FOP Java代码后,我设法使其正常工作。

描述性版本

主要思想是强制FOP使用自定义PDFRendererConfigurator,该自定义getCustomFontCollection()在执行PDFDocumentHandlerMaker时将返回所需的字体列表。

为此,我们需要创建自定义PDFDocumentHandler,该自定义makeIFDocumentHandler()将返回自定义PDFRendererConfigurator(表单方法getConfigurator()),而自定义PDFDocumentHandlerMaker将返回自定义RendererFactory(从FopFactory > RendererFactory > PDFDocumentHandlerMaker > PDFDocumentHandler > PDFRendererConfigurator方法),如上所述,它将列出自定义字体列表。

然后只需将自定义public class FopTest { public static void main(String[] args) throws Exception { // the XSL FO file StreamSource xsltFile = new StreamSource( Thread.currentThread().getContextClassLoader().getResourceAsStream("template.xsl")); // the XML file which provides the input StreamSource xmlSource = new StreamSource( Thread.currentThread().getContextClassLoader().getResourceAsStream("employees.xml")); // create an instance of fop factory FopFactory fopFactory = new FopFactoryBuilder(new File(".").toURI()).build(); RendererFactory rendererFactory = fopFactory.getRendererFactory(); rendererFactory.addDocumentHandlerMaker(new CustomPDFDocumentHandlerMaker()); // a user agent is needed for transformation FOUserAgent foUserAgent = fopFactory.newFOUserAgent(); // Setup output OutputStream out; out = new java.io.FileOutputStream("employee.pdf"); try { // Construct fop with desired output format Fop fop = fopFactory.newFop(MimeConstants.MIME_PDF, foUserAgent, out); // Setup XSLT TransformerFactory factory = TransformerFactory.newInstance(); Transformer transformer = factory.newTransformer(xsltFile); // Resulting SAX events (the generated FO) must be piped through to // FOP Result res = new SAXResult(fop.getDefaultHandler()); // Start XSLT transformation and FOP processing // That's where the XML is first transformed to XSL-FO and then // PDF is created transformer.transform(xmlSource, res); } finally { out.close(); } } } 添加到public class CustomPDFDocumentHandlerMaker extends PDFDocumentHandlerMaker { @Override public IFDocumentHandler makeIFDocumentHandler(IFContext ifContext) { CustomPDFDocumentHandler handler = new CustomPDFDocumentHandler(ifContext); FOUserAgent ua = ifContext.getUserAgent(); if (ua.isAccessibilityEnabled()) { ua.setStructureTreeEventHandler(handler.getStructureTreeEventHandler()); } return handler; } } 即可。

public class CustomPDFDocumentHandler extends PDFDocumentHandler { public CustomPDFDocumentHandler(IFContext context) { super(context); } @Override public IFDocumentHandlerConfigurator getConfigurator() { return new CustomPDFRendererConfigurator(getUserAgent(), new PDFRendererConfigParser()); } }

完整代码

FopTest.java

public class CustomPDFRendererConfigurator extends PDFRendererConfigurator {

    public CustomPDFRendererConfigurator(FOUserAgent userAgent, RendererConfigParser rendererConfigParser) {
        super(userAgent, rendererConfigParser);
    }

    @Override
    protected FontCollection getCustomFontCollection(InternalResourceResolver resolver, String mimeType)
            throws FOPException {

        List<EmbedFontInfo> fontList = new ArrayList<EmbedFontInfo>();
        try {
            FontUris fontUris = new FontUris(Thread.currentThread().getContextClassLoader().getResource("UbuntuMono-Bold.ttf").toURI(), null);
            List<FontTriplet> triplets = new ArrayList<FontTriplet>();
            triplets.add(new FontTriplet("UbuntuMono", Font.STYLE_NORMAL, Font.WEIGHT_NORMAL));
            EmbedFontInfo fontInfo = new EmbedFontInfo(fontUris, false, false, triplets, null, EncodingMode.AUTO, EmbeddingMode.AUTO);
            fontList.add(fontInfo);
        } catch (Exception e) {
            e.printStackTrace();
        }

        return createCollectionFromFontList(resolver, fontList);
    }

}

CustomPDFDocumentHandlerMaker.java

function getVal(){

    var firstVal= document.querySelector("input[name='price1']:checked");
    if (firstVal.checked){
       console.log(firstVal.value);

    } 
}

CustomPDFDocumentHandler.java

function getVal(){

    var firstVal= document.querySelector("input[name='price1']:checked");
    if (firstVal.checked){
        console.log(firstVal.value);
    } else 
        console.log(0);
    }
}

CustomPDFRendererConfigurator.java

function getVal(){

    var firstVal= document.querySelector("input[name='price1']:checked");
    if (firstVal.checked){
          console.log(firstVal.value);
    } 

    if (firstVal.checked === false){
          console.log(0);
    }

}

答案 1 :(得分:0)

是的,您可以这样做。您需要以编程方式设置FOP的第一个基本目录。

    fopFactory = FopFactory.newInstance();
    // for image base URL : images from Resource path of project
    String serverPath = request.getSession().getServletContext().getRealPath("/");
    fopFactory.setBaseURL(serverPath);
    // for fonts base URL :  .ttf from Resource path of project
    fopFactory.getFontManager().setFontBaseURL(serverPath);

然后使用FOB字体配置文件,它将使用以上基本路径。

只需将字体文件放在Web应用程序资源文件夹中,然后在FOP的字体配置文件中引用该路径即可。

注释后:以编程方式读取字体配置(不是首选的方式,还是仍按要求使用的简洁方式)

    //This is NON tested and PSEUDO code to get understanding of logic
    FontUris fontUris = new FontUris(new URI("<font.ttf relative path>"), null);
    EmbedFontInfo fontInfo = new EmbedFontInfo(fontUris, "is kerning enabled boolean", "is aldvaned enabled boolean", null, "subFontName");
    List<EmbedFontInfo> fontInfoList = new ArrayList<>();
    fontInfoList.add(fontInfo);
    //set base URL for Font Manager to use relative path of ttf file.
    fopFactory.getFontManager().updateReferencedFonts(fontInfoList);

您可以获取有关FOP相对路径https://xmlgraphics.apache.org/fop/2.2/configuration.html的更多信息