fop渲染到pdf中的一页

时间:2014-05-05 14:16:43

标签: java xslt apache-fop

我有一个代码,它运行apache fop对xml内容和xsl标记,并给我apache中间格式输出:

StreamSource contentSource = new StreamSource(xmlContentStream);
StreamSource transformSource = new StreamSource(xslMarkupStream);

ByteArrayOutputStream outStream = new ByteArrayOutputStream();
Transformer xslfoTransformer = getTransformer(transformSource);

FOUserAgent foUserAgent = fopFactory.newFOUserAgent();
IFDocumentHandler targetHandler = foUserAgent.getRendererFactory().createDocumentHandler(
                foUserAgent, MimeConstants.MIME_PDF);

FPSIFSerializer fpsSerializer = new FPSIFSerializer();

fpsSerializer.setContext(new IFContext(foUserAgent));
fpsSerializer.mimicDocumentHandler(targetHandler);
foUserAgent.setDocumentHandlerOverride(fpsSerializer);

Fop fop = fopFactory.newFop("application/X-fop-intermediate-format", foUserAgent, outStream);

DefaultHandler defaultHandler = fop.getDefaultHandler();

Result res = new SAXResult(defaultHandler);
xslfoTransformer.transform(contentSource, res);

然后我使用该中间格式文件来渲染pdf和png文件。 我可以在这里设置我自己的serilaizer(FPSIFSerializer())。

我有几页报告,但我不需要处理所有这些报告。有没有办法跳过一些页面或从IntermediateFormat中提取它们,所以我将能够例如仅将第一页渲染为png,然后将第二页渲染为pdf等? 那里 http://svn.apache.org/viewvc/xmlgraphics/fop/branches/archive/fop-1_1/examples/embedding/java/embedding/intermediate/ExampleConcat.java?view=markup 是一个如何通过IFConcatenator连接文件的例子,所以我想知道拆分多页文件的最佳方法?

Thank_you!

1 个答案:

答案 0 :(得分:0)

我完成它的方式是使用自定义文档处理程序。

/**
 * Custom Apache FOP Intermediate Format document handler which allows page skipping.
 * Not thread safe.
 */
public class IFPageFilter extends IFDocumentHandlerProxy {
private static final Logger LOGGER = LoggerFactory.getLogger(IFPageFilter.class);
private int currentPage;
private final int desiredPage;

/**
 * @param delegate The real document handler
 * @param desiredPage the page you want to render (1-based). Other pages will be skipped.
 */
public IFPageFilter(final IFDocumentHandler delegate, final int desiredPage) {
    super(delegate);
    this.desiredPage = desiredPage;
}


@Override
public void startPage(final int index, final String name, final String pageMasterName, final Dimension size) throws IFException {
    currentPage = index + 1;
    if (currentPage == desiredPage) {
        super.startPage(index, name, pageMasterName, size);
    } else {
        // do nothing
            LOGGER.debug("Page skipped");
    }
}

@Override
public IFPainter startPageContent() throws IFException {
    if (currentPage == desiredPage) {
        return super.startPageContent();
    } else {
        return EmptyPainter.getInstance();
    }
}

@Override
public void endPageContent() throws IFException {
    if (currentPage == desiredPage) {
        super.endPageContent();
    }
  }
}

然后你可以像这样附上你的处理程序:

final IFDocumentHandler targetHandler = FOP_FACTORY.getRendererFactory().createDocumentHandler(userAgent, mime);
    final IFPageFilter documentHandler = new IFPageFilter(targetHandler, page);
final ByteArrayOutputStream mimeOut = new ByteArrayOutputStream(XSL_STREAM_BUFFER_SIZE);

    IFUtil.setupFonts(documentHandler);

    // Tell the target handler where to write the PDF to
    targetHandler.setResult(new StreamResult(mimeOut));
    try (final InputStream is = ifStream.toInputStream()) {
        final Source src = new StreamSource(is);
        new IFParser().parse(src, documentHandler, userAgent);
    }
    return mimeOut;

您将获得输出流中唯一需要的页面。 类EmptyPainter是一个肮脏的黑客。它是apache IFPainter的空实现,它用于跳过页面内容并避免NPE。我对此并不满意,但这是我能够使其发挥作用的唯一方式。

请注意我使用的是FOP 1.1,如果你遇到这样的问题,那么值得看看后备箱 - 其中一些已经解决了。我想在主干中没有必要使用EmptyPainter进行肮脏的黑客攻击。

如果可以在这里做得更好,请提供建议。

由于