0

I have a code which runs apache fop against xml content and xsl markup and gives me the apache Intermediate Format output:

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

Then I use that Intermediate Format file to render pdf and png files out of it. I'm able to set up my own serilaizer here (FPSIFSerializer()).

I have several pages reports, but I don't need to process all of them. Is there any way to skip some pages or extract them from IntermediateFormat so I will be able e.g. to render only 1st page as png and then 2nd to pdf, etc ? There http://svn.apache.org/viewvc/xmlgraphics/fop/branches/archive/fop-1_1/examples/embedding/java/embedding/intermediate/ExampleConcat.java?view=markup is an example of how to concatenate files via IFConcatenator, so I wonder about the best way to split the multipage file?

Thank_you!

Eugene S
  • 99
  • 1
  • 11

1 Answers1

0

The way I've done it is using custom document handler.

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

Then you can attach your handler like that:

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;

and you will get the only page you need in the output stream. Class EmptyPainter is a dirty hack. It is empty implementation of apache IFPainter, it used here to skip page content and avoid NPE. I'm not happy about it, but that is the only way I was able to make it work.

Please note that I use FOP 1.1, and if you faced with such problems it worth to look at trunk - some of them already solved there. I guess dirty hack with EmptyPainter will not be necessary in trunk.

Please give tips if something could be done better here.

Thanks

Eugene S
  • 99
  • 1
  • 11