javapdfpdfbox

Adding Header to existing PDF File using PDFBox


I am trying to add a Header to an existing PDF file. It works but the table header in the existing PDF are messed up by the change in the font. If I remove setting the font then the header doesn't show up. Here is my code:

    // the document
    PDDocument doc = null;
    try
    {
        doc = PDDocument.load( file );

        List allPages = doc.getDocumentCatalog().getAllPages();
        //PDFont font = PDType1Font.HELVETICA_BOLD;

        for( int i=0; i<allPages.size(); i++ )
        {
            PDPage page = (PDPage)allPages.get( i );
            PDRectangle pageSize = page.findMediaBox();
            PDPageContentStream contentStream = new PDPageContentStream(doc, page, true, true,true);
            PDFont font = PDType1Font.TIMES_ROMAN;
            float fontSize = 15.0f;
            contentStream.beginText();
            // set font and font size
            contentStream.setFont( font, fontSize);
            contentStream.moveTextPositionByAmount(700, 1150);
            contentStream.drawString( message);
            contentStream.endText();

            //contentStream.
            contentStream.close();}

        doc.save( outfile );
    }
    finally
    {
        if( doc != null )
        {
            doc.close();
        }
    }
}`

Solution

  • Essentially you are running into a PDFBox bug in the current version 1.8.2.

    A workaround:

    Add a getFonts call of the page resources after creating the new content stream before using a font:

    PDPage page = (PDPage)allPages.get( i );
    PDRectangle pageSize = page.findMediaBox();
    PDPageContentStream contentStream = new PDPageContentStream(doc, page, true, true,true);
    page.getResources().getFonts();  // <<<<<<<<
    PDFont font = PDType1Font.TIMES_ROMAN;
    float fontSize = 15.0f;
    contentStream.beginText();
    

    The bug itself:

    The bug is in the method PDResources.addFont which is called from PDPageContentStream.setFont:

    public String addFont(PDFont font) 
    {
        return addFont(font, MapUtil.getNextUniqueKey( fonts, "F" ));
    }
    

    It uses the current content of the fonts member variable to determine a unique name for the new font resource on the page at hand. Unfortunately this member variable still can be (and in your case is) uninitialized at this time. This results in the MapUtil.getNextUniqueKey( fonts, "F" ) call to always return F0.

    The font variable then is initialized implicitly during the addFont(PDFont, String) call later.

    Thus, if unfortunately there already existed a font named F0 on that page, it is replaced by the new font.

    Having tested with your PDF this is exactly what happens in your case. As the existing font F0 uses some custom encoding while your replacement font uses a standard one, the text originally written using F0 now looks like gibberish.

    The work-around mentioned above implicitly initializes that member variable and, thus, prevents the font replacement.

    If you plan to use PDFBox in production for this task, you might want to report the bug.

    PS: As mentioned in the comments above there is another bug to observe in context with inherited resources. It should be brought to the PDFBox development's attention, too.

    PPS: The issue at hand meanwhile has been fixed in PDFBox for versions 1.8.3 and 2.0.0, cf. PDFBOX-1753.