Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
744 views
in Technique[技术] by (71.8m points)

itext7 - How can I add source PDF content to destination PDF using iText 7 without losing the header and footer?

I am using iText 7. I have two PDF files. The source PDF has some content. The destination PDF has header and footer. I have a requirement to add the content from source PDF to destination PDF in the middle of the page without overlapping header and footer of the destination PDF. What should the code be?

Below is my code and attached document is the screenshot of the source PDF file which needs to be embedded in the final.pdf file:

import java.io.File;
import java.io.FileOutputStream;
import java.net.MalformedURLException;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

import com.itextpdf.io.font.FontProgram;
import com.itextpdf.io.font.FontProgramFactory;
import com.itextpdf.io.font.PdfEncodings;
import com.itextpdf.io.image.ImageDataFactory;
import com.itextpdf.kernel.events.Event;
import com.itextpdf.kernel.events.IEventHandler;
import com.itextpdf.kernel.events.PdfDocumentEvent;
import com.itextpdf.kernel.font.PdfFont;
import com.itextpdf.kernel.font.PdfFontFactory;
import com.itextpdf.kernel.geom.PageSize;
import com.itextpdf.kernel.geom.Rectangle;
import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfPage;
import com.itextpdf.kernel.pdf.PdfWriter;
import com.itextpdf.kernel.pdf.canvas.PdfCanvas;
import com.itextpdf.kernel.pdf.xobject.PdfFormXObject;
import com.itextpdf.layout.Canvas;
import com.itextpdf.layout.Document;
import com.itextpdf.layout.Style;
import com.itextpdf.layout.borders.Border;
import com.itextpdf.layout.borders.SolidBorder;
import com.itextpdf.layout.element.Cell;
import com.itextpdf.layout.element.Image;
import com.itextpdf.layout.element.Paragraph;
import com.itextpdf.layout.element.Table;
import com.itextpdf.layout.element.Text;
import com.itextpdf.layout.font.FontProvider;
import com.itextpdf.layout.property.HorizontalAlignment;
import com.itextpdf.layout.property.TextAlignment;
import com.itextpdf.layout.property.UnitValue;
import com.itextpdf.layout.property.VerticalAlignment;

public class TestPdf {

    public static void main(String[] args) {

        String uuid = UUID.randomUUID().toString();
        try {
            @SuppressWarnings("resource")
            PdfWriter writer = new PdfWriter(new FileOutputStream(new File(Paths.get("Output").toAbsolutePath()+"/final.pdf"))).setSmartMode(true);
            PdfDocument pdfDoc = new PdfDocument(writer);
            pdfDoc.setDefaultPageSize(PageSize.A4.rotate());
            String fonts[] = {Paths.get("fonts").toAbsolutePath() + "/TREBUC.TTF", Paths.get("fonts").toAbsolutePath() + "/TREBUCBD.TTF", Paths.get("fonts").toAbsolutePath() + "/TREBUCBI.TTF",Paths.get("fonts").toAbsolutePath() + "/TREBUCIT.TTF"};
            FontProvider fontProvider = new FontProvider();
            Map<String, PdfFont> pdfFontMap = new HashMap();
            for (String font : fonts) {
                FontProgram fontProgram = FontProgramFactory.createFont(font);
                if(font.endsWith("TREBUC.TTF")) {
                    pdfFontMap.put("NORMAL", PdfFontFactory.createFont(fontProgram, PdfEncodings.WINANSI, true));
                } else if(font.endsWith("TREBUCBD.TTF")) {
                    pdfFontMap.put("BOLD", PdfFontFactory.createFont(fontProgram, PdfEncodings.WINANSI, true));
                } else if(font.endsWith("TREBUCBI.TTF")) {
                    pdfFontMap.put("BOLD_ITALIC", PdfFontFactory.createFont(fontProgram, PdfEncodings.WINANSI, true));
                } else if(font.endsWith("TREBUCIT.TTF")) {
                    pdfFontMap.put("ITALIC", PdfFontFactory.createFont(fontProgram, PdfEncodings.WINANSI, true));
                }

                fontProvider.addFont(fontProgram);
            }
            TestPdf testPdf = new TestPdf();
            NormalPageHeader headerHandler = testPdf.new NormalPageHeader(Paths.get("images").toAbsolutePath() + "\logo.png", pdfFontMap);
            pdfDoc.addEventHandler(PdfDocumentEvent.START_PAGE, headerHandler);
            PageEndEvent pageEndEvent = testPdf.new PageEndEvent(Paths.get("images").toAbsolutePath() + "\FooterLineExternal.png" ,pdfFontMap);
            pdfDoc.addEventHandler(PdfDocumentEvent.END_PAGE, pageEndEvent);
            Document doc = new Document(pdfDoc);

            doc.getPageEffectiveArea(PageSize.A4.rotate());
            Table imageTable = new Table(1);
            imageTable.setBorder(Border.NO_BORDER);
            imageTable.setWidth(UnitValue.createPercentValue(100));
            Cell cell = new Cell();
            Paragraph paragraph = new Paragraph("Title");
            paragraph.setVerticalAlignment(VerticalAlignment.TOP);
            cell.add(paragraph);
            cell.setBorder(Border.NO_BORDER);
            cell.setPaddingTop(50);
            imageTable.addCell(cell);
            doc.add(imageTable);
            doc.close();
            System.out.println("Converted to PDF Succesfully >>> convertedSvg_"+uuid+".pdf");
         }
         catch(Exception e){
             e.printStackTrace();
             System.out.println("Error Occured while converting to PDF = " + e.getMessage());
         }
    }


    class NormalPageHeader implements IEventHandler {

        String header;
        Map<String, PdfFont> font;
        public NormalPageHeader(String header, Map<String, PdfFont> font) {
            this.header = header;
            this.font = font;
        }

        @Override
        public void handleEvent(Event event) {
            //Retrieve document and
            PdfDocumentEvent docEvent = (PdfDocumentEvent) event;
            PdfDocument pdf = docEvent.getDocument();
            PdfPage page = docEvent.getPage();
            Rectangle pageSize = page.getPageSize();
            PdfCanvas pdfCanvas = new PdfCanvas(
            page.getLastContentStream(), page.getResources(), pdf);
            Canvas canvas = new Canvas(pdfCanvas, pdf, pageSize);
            canvas.setFontSize(10f);
            Table table = new Table(3);
            table.setBorder(Border.NO_BORDER);
            table.setWidth(UnitValue.createPercentValue(100));
            Cell leftCell = new Cell();
            leftCell.setFont(font.get("NORMAL"));
            leftCell.setPaddingTop(15);
            leftCell.setPaddingLeft(20);
            leftCell.setBorder(Border.NO_BORDER);
            leftCell.setBorderBottom(new SolidBorder(0.5f));
            leftCell.setWidth(UnitValue.createPercentValue(33.3f));
            Text userLabel = new Text("Username: ");
            userLabel.setBold();
            Paragraph paragraph = new Paragraph(userLabel);
            Cell middleCell = new Cell();
            middleCell.setFont(font.get("NORMAL"));
            middleCell.setPaddingTop(15);
            middleCell.setBorder(Border.NO_BORDER);
            middleCell.setBorderBottom(new SolidBorder(0.5f));
            middleCell.setWidth(UnitValue.createPercentValue(33.3f));
            paragraph = new Paragraph("Main Header");
            paragraph.setTextAlignment(TextAlignment.CENTER);
            paragraph.setBold();
            paragraph.setFontSize(12);
            middleCell.add(paragraph);
            String programString = "Sample header";
            paragraph = new Paragraph(programString);
            paragraph.setTextAlignment(TextAlignment.CENTER);
            paragraph.setBold();
            paragraph.setFontSize(10);
            middleCell.add(paragraph);

            table.addCell(middleCell);
            Cell rightCell = new Cell();
            rightCell.setFont(font.get("NORMAL"));
            rightCell.setPaddingTop(20);
            rightCell.setWidth(UnitValue.createPercentValue(33.3f));
            rightCell.setHorizontalAlignment(HorizontalAlignment.RIGHT);
            rightCell.setBorder(Border.NO_BORDER);
            rightCell.setBorderBottom(new SolidBorder(0.5f));
            rightCell.setPaddingRight(20);
            //Write text at position
            Image img;
            try {
                img = new Image(ImageDataFactory.create(header));
                img.setHorizontalAlignment(HorizontalAlignment.RIGHT);
                Style style = new Style();
                style.setWidth(91);
                style.setHeight(25);

                 img.addStyle(style);
                 rightCell.add(img);
                 table.addCell(rightCell);
                 table.setMarginLeft(15);
                 table.setMarginRight(15);
                 canvas.add(table);
            }
            catch (MalformedURLException e) {
                e.printStackTrace();
            }
        }
    }

    class PageEndEvent implements IEventHandler {

         protected PdfFormXObject placeholder;
         protected float side = 20;
         protected float x = 300;
         protected float y = 10;
         protected float space = 4.5f;
         private String bar;
         protected float descent = 3;
         Map<String, PdfFont> font;
         public PageEndEvent(String bar, Map<String, PdfFont> font) {
             this.bar = bar;
             this.font = font;
             placeholder =new PdfFormXObject(new Rectangle(0, 0, side, side));
         }

         @Override
         public void handleEvent(Event event) {
             Table table = new Table(3);
             table.setBorder(Border.NO_BORDER);
             table.setWidth(UnitValue.createPercentValue(100));
             Cell confCell = new Cell();
             confCell.setFont(font.get("NORMAL"));
             confCell.setPaddingTop(15);
             confCell.setPaddingLeft(20);
             confCell.setBorder(Border.NO_BORDER);
             confCell.setBorderBottom(new SolidBorder(0.5f));
             confCell.setWidth(UnitValue.createPercentValue(100));
             PdfDocumentEvent docEvent = (PdfDocumentEvent) event;
             PdfDocument pdf = docEvent.getDocument();
             PdfPage page = docEvent.getPage();
             Rectangle pageSize = page.getPageSize();
             PdfCanvas pdfCanvas = new PdfCanvas(
             page.getLastContentStream(), page.getResources(), pdf);
             Canvas canvas = new Canvas(pdfCanvas, pdf, pageSize);
             Image img;
             try {
                 img = new Image(ImageDataFactory.create(bar));
                 img.setHorizontalAlignment(HorizontalAlignment.LEFT);
                 Style style = new Style();
                 style.setWidth(UnitValue.createPercentValue(100));
                 style.setHeight(50);
                 img.addStyle(style);
                 Paragraph p = new Paragraph().add("Test: Confidential");
                 p.setFont(font.get("NORMAL"));
                 p.setFontSize(8);
                 p.setFontColor(com.itextpdf.kernel.colors.ColorConstants.GRAY);
                 canvas.showTextAligned(p, x, y, TextAlignment.CENTER);
                 pdfCanvas.addXObject(placeholder, x + space, y - descent);
                 pdfCanvas.release();
             }
             catch (MalformedURLException e) {
                 e.printStackTrace();
             }
         }

         public void writeTotal(PdfDocument pdf) {

             Canvas canvas = new Canvas(placeholder, pdf);

             canvas.showTextAligned(String.valueOf(pdf.getNumberOfPages()),
                              

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

First off, some words on the iText architecture behind some constructs you use:

When you use a Document instance to add content to a document that iText shall layout automatically, the assumption is that the area where iText can layout stuff is the whole page minus the page margins.

Thus, if you add further page material via other channels than the Document, e.g. like you do in your NormalPageHeader headerHandler and your PageEndEvent pageEndEvent, it is your responsibility to do so outside the layout area explained above, i.e. in the margin areas. (Unless that additional material is background stuff, like a water sign...)

For this you should set the margins large enough to guarantee that your further material is in the margins. By default the page margins are set to 36pt on each side of the page which usually is enough for a single line header or footer but not really for multi-line ones.

In your code you create a header which requires at least some 52pt plus a bit to prevent the content iText will layout from touching the header line.

Keeping that in mind it is pretty straight forward to insert a given PdfPage sourcePage into your page:

...
NormalPageHeader headerHandler = testPdf.new NormalPageHeader(Paths.get("images").toAbsolutePath() + "\logo.png", pdfFontMap);
pdfDoc.addEventHandler(PdfDocumentEvent.START_PAGE, headerHandler);
PageEndEvent pageEndEvent = testPdf.new PageEndEvent(Paths.get("images").toAbsolutePath() + "\FooterLineExternal.png" ,pdfFontMap);
pdfDoc.addEventHandler(PdfDocumentEvent.END_PAGE, pageEndEvent);

Document doc = new Document(pdfDoc);
doc.setTopMargin(55);
PdfFormXObject xobject = sourcePage.copyAsFormXObject(pdfDoc);
Rectangle xobjectBoundaryBox = xobject.getBBox().toRectangle();
xobject.getPdfObject().put(PdfName.Matrix, new PdfArray(new float[] {1, 0, 0, 1, -xobjectBoundaryBox.getLeft(), -xobjectBoundaryBox.getBottom()}));
Image image = new Image(xobject);
image.setAutoScale(true);
doc.add(image);

doc.close();
...

(excerpt from InsertInSpace helper insertIntoNithinTestFile)


If you use the original source page as is, the above code will insert it including all margin space. If you don't want this but instead cut that space of, you can proceed as follows to determine the actual bounding box of the page content, reduce the page to that box, and forward it to the method insertIntoNithinTestFile above, assuming page 1 of PdfDocument pdfDocument shall be processed:

PdfDocumentContentParser contentParser = new PdfDocumentContentParser(pdfDocument);
MarginFinder strategy = contentParser.processContent(1, new MarginFinder());

PdfPage page = pdfDocument.getPage(1);
page.setCropBox(strategy.getBoundingBox());
page.setMediaBox(strategy.getBoundingBox());
insertIntoNithinTestFile(page, "test-InsertIntoNithinTestFile.pdf");

(InsertInSpace test testInsertSimpleTestPdf)

The MarginFinder is a port of the iText5 MarginFinder to iText 7:

public class MarginFinder implements IEventListener {
    public Rectangle getBoundingBox() {
        return boundingBox != null ? boundingBox.clone() : null;
    }

    @Override
    public void eventOccurred(IEventData data, EventType type) {
        if (data instanceof ImageRenderInfo) {
            ImageRenderInfo imageData = (ImageRenderInfo) data;
            Matrix ctm = imageData.getImageCtm();
            for (Vector unitCorner : UNIT_SQUARE_CORNERS) {
                Vector corner = unitCorner.cross(ctm);
                addToBoundingBox(new Rectangle(corner.get(Vector.I1), corner.get(Vector.I2), 0, 0));
            }
        } else if (data instanceof TextRenderInfo) {
            TextRenderInfo textRenderInfo = (TextRenderInfo) data;
            addToBoundingBox(textRenderInfo.getAscentLine().getBoundingRectangle());
            addToBoundingBox(textRenderInfo.getDescentLine().getBoundingRectangle());
        } else if (data instanceof PathRenderInfo) {
            PathRenderInfo renderInfo = (PathRenderInfo) data;
            if (renderInfo.getOperation() != PathRenderInfo.NO_OP)
            {
                Matrix ctm = renderInfo.getCtm();
                Path path = renderInfo.getPath();
                for (Subpath subpath : path.getSubpaths())
                {
                    for (Point point2d : subpath.getPiecewiseLinearApproximation())
                    {
                        Vector vector = new Vector((float)point2d.getX(), (float)point2d.getY(), 1);
                        vector = vector.cross(ctm);
                        addToBoundingBox(new Rectangle(vector.get(Vector.I1), vector.get(Vector.I2), 0, 0));
                    }
                }
            }
        } else if (data != null) {
            logger.fine(String.format("Ignored %s event, class %s.", type, data.getClass().getSimpleName()));
        } else {
            logger.fine(String.format("Ignored %s event with null data.", type));
        }
    }

    @Override
    public Set<EventType> getSupportedEvents() {
        return null;
    }

    void addToBoundingBox(Rectangle rectangle) {
        if (boundingBox == null)
            boundingBox = rectangle.clone();
        else
            boundingBox = Rectangle.getCommonRectangle(boundingBox, rectangle);
    }

    Rectangle boundingBox = null;
    Logger logger = Logger.getLogger(MarginFinder.class.getName());
    static List<Vector> UNIT_SQUARE_CORNERS = Arrays.asList(new Vector(0,0,1), new Vector(1,0,1), new Vector(1,1,1), new Vector(0,1,1));
}

(MarginFinder.java)


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

1.4m articles

1.4m replys

5 comments

57.0k users

...