如何在不丢失页眉和页脚的情况下使用IText7将源PDF内容添加到目标PDF?

时间:2019-06-10 07:59:36

标签: pdf itext7

我正在使用Itext7。我有两个PDF。源PDF包含一些内容。目标PDF具有页眉和页脚。我需要将内容从源PDF添加到页面中间的目标PDF中,而不会重叠目标PDF的页眉和页脚。谁能帮我提供代码?

下面是我的代码,附件是源PDF的屏幕截图,需要将其嵌入final.pdf

enter image description here

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()),

                     0, descent, TextAlignment.LEFT);

         }

     }

}

1 个答案:

答案 0 :(得分:1)

首先,在您使用的某些构造背后的iText架构上写一些话:

当您使用Document实例向iText应该自动布局的文档中添加内容时,假设iText可以布局内容的区域是整个页面减去页面边距。

因此,如果您通过Document以外的其他渠道添加更多页面材料,例如就像您在NormalPageHeader headerHandlerPageEndEvent pageEndEvent中所做的那样,您的责任是在上述布局区域之外进行操作,即在页边空白处地区。 (除非其他材料是背景材料,例如水印……)

为此,您应该将页边距设置得足够大,以确保其他材料在页边距中。默认情况下,页面两边的页边距设置为36pt,通常对于单行页眉或页脚而言就足够了,但对于多行页眉或页脚而言却不足。

在代码中,您将创建一个标题,该标题至少需要52pt加一点,以防止iText布局的内容触及标题行。

请记住,将给定的PdfPage sourcePage插入页面非常简单:

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

(摘录自InsertInSpace助手insertIntoNithinTestFile


如果按原样使用原始源页面,则上面的代码将插入其中,包括所有页边距空间。如果您不希望这样做,而是减少其空间,则可以按照以下步骤确定页面内容的实际边界框,将页面缩小到该框,然后将其转发到上面的方法insertIntoNithinTestFile,假设PdfDocument pdfDocument的第1页将被处理:

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测试testInsertSimpleTestPdf

MarginFinder是iText5 MarginFinder到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