Apache FOP - есть ли способ встроить шрифт программно? - PullRequest
0 голосов
/ 25 февраля 2019

При создании PDF с использованием Apache FOP можно встроить шрифт в файл конфигурации.Проблема возникает, когда приложение является веб-приложением, и необходимо встроить шрифт, который находится внутри WAR-файла (рассматривается как ресурс).

Недопустимо использовать структуру папок определенного контейнера, чтобы точно определить, где именнонаходится война (когда в файле конфигурации xml мы устанавливаем тег на ./, он устанавливается на базовую папку запущенного контейнера, например C:\Tomcat\bin).

Итак, вопрос: кто-нибудь знает, как встроить шрифт программно?

Ответы [ 2 ]

0 голосов
/ 26 февраля 2019

После прохождения большого количества Java-кода FOP мне удалось заставить его работать.

Описательная версия

Основная идея состоит в том, чтобы заставить FOP использовать пользовательский PDFRendererConfigurator, который будет возвращать желаемый шрифтсписок при выполнении getCustomFontCollection().

Для этого нам нужно создать пользовательский PDFDocumentHandlerMaker, который будет возвращать пользовательский PDFDocumentHandler (метод формы makeIFDocumentHandler()), который в свою очередь будет возвращать наш пользовательский PDFRendererConfigurator (из метода getConfigurator()), который, как указано выше, устанавливает список пользовательских шрифтов.

Затем просто добавьте пользовательский PDFDocumentHandlerMaker к RendererFactory, и он будет работать.

FopFactory > RendererFactory > PDFDocumentHandlerMaker > PDFDocumentHandler > PDFRendererConfigurator

Полный код

FopTest.java

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();
        }

    }

}

CustomPDFDocumentHandlerMaker.java

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;
    }

}

CustomPDFDocumentHandler.java

public class CustomPDFDocumentHandler extends PDFDocumentHandler {

    public CustomPDFDocumentHandler(IFContext context) {
        super(context);
    }

    @Override
    public IFDocumentHandlerConfigurator getConfigurator() {
        return new CustomPDFRendererConfigurator(getUserAgent(), new PDFRendererConfigParser());
    }

}

CustomPDFRendererConfigurator.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);
    }

}
0 голосов
/ 25 февраля 2019

Да, вы можете сделать это.Вам необходимо программно установить первый базовый каталог 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. Он будет использовать вышеуказанный базовый путь.

Просто поместите свои файлы шрифтов в папку ресурсов веб-приложений и укажите этот путь в файле конфигурации шрифта 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

...