使用PDFBox教程以Java生成PDF

时间:2020-01-09 10:35:28  来源:igfitidea点击:

在本文中,我们将介绍使用Apache PDFBox以Java生成PDF的另一种方法。

Apache PDFBox库

Apache PDFBox库(https://pdfbox.apache.org/)是用于处理PDF文档的开源Java工具。该项目允许创建新的PDF文档,操作现有文档以及从文档中提取内容的功能。

这篇文章中给出了使用PDFBox和Java生成PDF的示例。

PDFBox的Maven依赖

<dependency>
  <groupId>org.apache.pdfbox</groupId>
  <artifactId>pdfbox</artifactId>
  <version>2.0.13</version>
</dependency>

使用Java和PDFBox的HelloWorld PDF

我们将首先创建一个简单的HelloWorld PDF,它还会显示内容的字体和文本颜色设置。要使用PDFBox创建PDF并向其中添加内容,我们需要执行以下步骤。

  • 使用PDDocument类创建一个新的PDF文档。实例化此类,我们可以创建一个空的PDF文档。

  • 使用PDPage类将页面添加到该空白PDF文档。这会将空白页添加到PDF文档。

  • 使用PDPageContentStream类写入该页面。

  • 我们需要在开始文本操作之前调用PDPageContentStream类的beginText()方法,并需要endText()方法结束文本操作。

  • 要设置行的起始位置,请使用newLineAtOffset()方法。页面上的原始位置在左下角,我们需要将其移到希望文本开始的位置。

import java.awt.Color;
import java.io.IOException;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDPageContentStream;
import org.apache.pdfbox.pdmodel.font.PDType1Font;

public class HelloWorldPDF {
  public static final String CREATED_PDF = "F://theitroad//result//PDFBox//HelloWorld.pdf";
  public static void main(String[] args) {
    try {
      PDDocument pdfDoc = new PDDocument();
      PDPage firstPage = new PDPage();
      // add page to the PDF document
      pdfDoc.addPage(firstPage);
      // For writing to a page content stream
      try(PDPageContentStream cs = new PDPageContentStream(pdfDoc, firstPage)){
        cs.beginText();
        // setting font family and font size
        cs.setFont(PDType1Font.COURIER, 15);
        // color for the text
        cs.setNonStrokingColor(Color.RED);
        // starting position
        cs.newLineAtOffset(20, 750);
        cs.showText("Hello World PDF created using PDFBox");
        // go to next line
        cs.newLine();
        cs.endText();
      }
      // save PDF document
      pdfDoc.save(CREATED_PDF);
      pdfDoc.close();
    } catch (IOException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
  }
}

使用PDFBox将多行和多行文本添加到PDF

如果我们必须在PDF中添加多行,并且文本跨越多行,那么我们需要使用的其他方法是

  • 使用PDPageContentStream类的newLine()方法移至下一行文本的开头。这需要设置引线,可以使用setLeading()方法完成。

  • 对于跨多行的文本,PDFBox不提供支持,因此我们需要使用页面允许的宽度并使用字体大小和宽度来计算该行中每个单词所占用的空间。

import java.awt.Color;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDPageContentStream;
import org.apache.pdfbox.pdmodel.font.PDFont;
import org.apache.pdfbox.pdmodel.font.PDType1Font;

public class CreatePDF {
  public static final String CREATED_PDF = "F://theitroad//result//PDFBox//Content.pdf";
  public static void main(String[] args) {
    try {
      PDDocument pdfDoc = new PDDocument();
      PDPage firstPage = new PDPage();
      // add page to the PDF document
      pdfDoc.addPage(firstPage);
      // For writing to a page content stream
      try(PDPageContentStream cs = new PDPageContentStream(pdfDoc, firstPage)){
        cs.beginText();
        cs.setFont(PDType1Font.COURIER, 15);
        cs.newLineAtOffset(20, 750);
        cs.setLeading(12);
        cs.showText("Hello World PDF created using PDFBox");
        cs.newLine();
        String text = "This text spans multiple lines and it is added to the PDF dcoument generated using PDFBox";
        showMultiLineText(text, 20, 762, 580, firstPage, cs, PDType1Font.COURIER, 15);
        cs.setFont(PDType1Font.TIMES_BOLD, 15);
        cs.setNonStrokingColor(Color.RED);
        cs.showText("While adding this line font and color settings are changed.");
        cs.newLine();
        cs.endText();
      }
      pdfDoc.save(CREATED_PDF);
      pdfDoc.close();
    } catch (IOException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
  }
	
  private static void showMultiLineText(String text, int x, int y, int allowedWidth, PDPage page, PDPageContentStream contentStream, PDFont font, int fontSize) throws IOException {
    List<String> lines = new ArrayList<String>();
    String line = "";
    // split the text on spaces
    String[] words = text.split(" ");
    for(String word : words) {
      if(!line.isEmpty()) {
        line += " ";
      }
      // check if adding the word to the line surpasses the width of the page
      int size = (int) (fontSize * font.getStringWidth(line + word) / 1000);
      if(size > allowedWidth) {
        // if line + word surpasses the width of the page, add the line without the current word
        lines.add(line);
        // start new line with the current word
        line = word;
      } else {
        // if line + word fits the page width, add the current word to the line
        line += word;
      }
    }
    lines.add(line);
    for(String ln : lines) {
      System.out.println("Line- " + ln);    
      contentStream.showText(ln);
      contentStream.newLine();
    }
  }
}

使用PDFBox将文本添加到现有PDF

如果要将新页面添加到现有的PDF文档中,则可以使用PDDocument类的load()方法加载现有的PDF。

import java.io.File;
import java.io.IOException;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDPageContentStream;
import org.apache.pdfbox.pdmodel.font.PDType1Font;

public class CreatePDF {
  public static final String CREATED_PDF = "F://theitroad//result//PDFBox//Content.pdf";
  public static void main(String[] args) {
    try {
      // Load existing PDF
      PDDocument pdfDoc = PDDocument.load(new File(CREATED_PDF));
      PDPage page = new PDPage();
      // add page to the PDF document
      pdfDoc.addPage(page);
      // For writing to a page content stream
      try(PDPageContentStream cs = new PDPageContentStream(pdfDoc, page)){
        cs.beginText();
        cs.setFont(PDType1Font.TIMES_ROMAN, 12);
        cs.newLineAtOffset(20, 750);
        cs.setLeading(12);
        cs.showText("This is a new page added to an existing PDF document");
        cs.newLine();
        cs.endText();
      }
      pdfDoc.save(CREATED_PDF);
      pdfDoc.close();
    } catch (IOException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
  }
}

使用PDFBox将文本文件转换为PDF

在Java示例中,有一个文本文件(Test.txt),可使用PDFBox转换为PDF。在此示例中,我们还将介绍以下场景:除了可能跨越多行的文本之外,内容还可能跨越PDF中的多个页面。在PDFBox中,必须先创建每个新页面并将其添加到文档中,然后才能将内容写入该页面。
对于PDFBox中多个页面中的内容,我们需要跟踪页面中内容的高度,当该高度超过允许的高度时,添加一个新页面。允许的高度可能会根据文档类型而有所不同,在此示例中,将考虑A4页面大小。
当前高度是通过将写入PDF文档的每一行的行高加到当前高度上来计算的。

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDPageContentStream;
import org.apache.pdfbox.pdmodel.font.PDFont;
import org.apache.pdfbox.pdmodel.font.PDType1Font;

public class CreatePDF {
  // Text file that has to be converted
  public static final String SOURCE_FILE = "F://theitroad//result//Test.txt";
  public static final String CREATED_PDF = "F://theitroad//result//PDFBox//Content.pdf";
  static double currentHeight = 0;
  static PDPageContentStream cs = null;
  public static void main(String[] args) {
    try {
      PDDocument pdfDoc = new PDDocument();
      // for text file
      BufferedReader br = new BufferedReader(new FileReader(SOURCE_FILE));
      PDPage page = new PDPage();
      // add page to the PDF document
      pdfDoc.addPage(page);
      String line;
      cs = new PDPageContentStream(pdfDoc, page);
      cs.beginText();
      cs.setFont(PDType1Font.TIMES_ROMAN, 12);
      cs.newLineAtOffset(20, 750);
      cs.setLeading(12);
      // Read text file line by line
      while ((line = br.readLine()) != null) {
        System.out.println("Line-- " + line);
        showMultiLineText(pdfDoc, line, 20, 750, 580, 820, page, PDType1Font.TIMES_ROMAN, 15);				
      }				
      if(cs != null) {
        cs.endText();
        cs.close();
      }
      pdfDoc.save(CREATED_PDF);
      br.close();
      pdfDoc.close();
    } catch (IOException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
  }
	
  /**
   * 
   * @param pdfDoc
   * @param text
   * @param x
   * @param y
   * @param allowedWidth - allowed width for the line before content goes to next line
   * @param allowedHeight - Allowed height for the page before another page is added
   * @param page
   * @param font
   * @param fontSize
   * @throws IOException
   */
  private static void showMultiLineText(PDDocument pdfDoc, String text, int x, int y, int allowedWidth, double allowedHeight, PDPage page, PDFont font, int fontSize) throws IOException {
    List<String> lines = new ArrayList<String>();
    String line = "";
    // split the text on spaces
    String[] words = text.split(" ");
    for(String word : words) {
      if(!line.isEmpty()) {
        line += " ";
      }
      // check if adding the word to the line surpasses the width of the page
      int size = (int) (fontSize * font.getStringWidth(line + word) / 1000);
      if(size > allowedWidth) {
        // if line + word surpasses the width of the page, add the line without the current word
        lines.add(line);
        // start new line with the current word
        line = word;
      } else {
        // if line + word fits the page width, add the current word to the line
        line += word;
      }
    }
    lines.add(line);

    for(String ln : lines) {
      System.out.println("Line- " + ln); 
      // for each line add line height to current height 
      // line height = 1.2 * fontSize is taken here 
      currentHeight = currentHeight + 1.2 * fontSize;
      System.out.println("currentHeight " + currentHeight);

      if(currentHeight >= allowedHeight) {
        System.out.println("adding new page " + currentHeight);
        // When current height is more than allowed height for the page
        // create a new page
        page = new PDPage();
        // add page to the PDF document
        pdfDoc.addPage(page);
        // reset currentHeight
        currentHeight = 0;
        cs.endText();
        cs.close();
        cs = new PDPageContentStream(pdfDoc, page);
        cs.beginText();
        cs.setFont(PDType1Font.TIMES_ROMAN, 12);
        cs.newLineAtOffset(20, 750);
        cs.setLeading(12);
      }
      cs.showText(ln);
      cs.newLine();  
    }
  }
}

使用PDFBox将图像添加到PDF文档

要将图像添加到PDF文档,请使用PDFBox库中的PDImageXObject类。

import java.io.IOException;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDPageContentStream;
import org.apache.pdfbox.pdmodel.font.PDType1Font;
import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject;

public class PDFImage {
  public static final String CREATED_PDF = "F://theitroad//result//PDFBox//Image.pdf";
  public static void main(String[] args) {		
    PDDocument pdfDoc;
    try {
      pdfDoc = new PDDocument();	
      PDPage page = new PDPage();
      pdfDoc.addPage(page);
      // Create image object using the image location
      PDImageXObject image = PDImageXObject.createFromFile("images//PDFBox image.png", pdfDoc);
      try(PDPageContentStream cs = new PDPageContentStream(pdfDoc, page)){
        cs.beginText();
        // setting font family and font size
        cs.setFont(PDType1Font.HELVETICA_BOLD, 14);
        // starting position in the page
        cs.newLineAtOffset(20, 700);
        cs.setLeading(12);
        cs.showText("In this page an image is added using PDFBox");
        cs.newLine();
        cs.endText();
        cs.drawImage(image, 20, 550);
      }
      pdfDoc.save(CREATED_PDF);
      pdfDoc.close();
        
    }catch (IOException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }		
  }
}