├── src ├── main │ ├── resources │ │ ├── song.png │ │ ├── simfang.ttf │ │ └── VAT_INVOICE.pdf │ └── java │ │ └── utils │ │ └── PDFBoxDemo.java └── test │ └── java │ └── utils │ └── AppTest.java └── pom.xml /src/main/resources/song.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dongdongdeng/pdfboxDemo/HEAD/src/main/resources/song.png -------------------------------------------------------------------------------- /src/main/resources/simfang.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dongdongdeng/pdfboxDemo/HEAD/src/main/resources/simfang.ttf -------------------------------------------------------------------------------- /src/main/resources/VAT_INVOICE.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dongdongdeng/pdfboxDemo/HEAD/src/main/resources/VAT_INVOICE.pdf -------------------------------------------------------------------------------- /src/test/java/utils/AppTest.java: -------------------------------------------------------------------------------- 1 | package DDD; 2 | 3 | import static org.junit.Assert.assertTrue; 4 | 5 | import org.junit.Test; 6 | 7 | /** 8 | * Unit test for simple App. 9 | */ 10 | public class AppTest 11 | { 12 | /** 13 | * Rigorous Test :-) 14 | */ 15 | @Test 16 | public void shouldAnswerWithTrue() 17 | { 18 | assertTrue( true ); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 4.0.0 6 | 7 | Utils 8 | Utils.ddd 9 | 1.0-SNAPSHOT 10 | 11 | DDD 12 | 13 | http://www.example.com 14 | 15 | 16 | UTF-8 17 | 1.7 18 | 1.7 19 | 20 | 21 | 22 | 23 | junit 24 | junit 25 | 4.11 26 | test 27 | 28 | 29 | 30 | org.apache.httpcomponents 31 | httpclient 32 | 4.5.6 33 | 34 | 35 | 36 | joda-time 37 | joda-time 38 | 2.9.4 39 | 40 | 41 | 42 | 43 | org.apache.pdfbox 44 | pdfbox 45 | 2.0.13 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | maven-clean-plugin 55 | 3.0.0 56 | 57 | 58 | 59 | maven-resources-plugin 60 | 3.0.2 61 | 62 | 63 | maven-compiler-plugin 64 | 3.7.0 65 | 66 | 67 | maven-surefire-plugin 68 | 2.20.1 69 | 70 | 71 | maven-jar-plugin 72 | 3.0.2 73 | 74 | 75 | maven-install-plugin 76 | 2.5.2 77 | 78 | 79 | maven-deploy-plugin 80 | 2.8.2 81 | 82 | 83 | 84 | 85 | 86 | -------------------------------------------------------------------------------- /src/main/java/utils/PDFBoxDemo.java: -------------------------------------------------------------------------------- 1 | package utils; 2 | 3 | import org.apache.pdfbox.pdmodel.PDDocument; 4 | import org.apache.pdfbox.pdmodel.PDPage; 5 | import org.apache.pdfbox.pdmodel.PDPageContentStream; 6 | import org.apache.pdfbox.pdmodel.font.PDFont; 7 | import org.apache.pdfbox.pdmodel.font.PDType0Font; 8 | import org.apache.pdfbox.pdmodel.font.PDType1Font; 9 | import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject; 10 | import org.apache.pdfbox.pdmodel.graphics.state.PDExtendedGraphicsState; 11 | import org.apache.pdfbox.util.Matrix; 12 | 13 | import java.io.File; 14 | import java.io.IOException; 15 | import java.io.InputStream; 16 | import java.util.ArrayList; 17 | import java.util.List; 18 | 19 | /** 20 | * PDFBox: Hello world! 21 | * 22 | */ 23 | public class PDFBoxDemo 24 | { 25 | private static PDFont FONT = PDType1Font.HELVETICA; 26 | private static float FONT_SIZE = 10; 27 | private static final float LEADING = -1.5f * FONT_SIZE; 28 | 29 | public static void showTextByLeft(PDPageContentStream overContent, String txt, String def, float x, float y) throws Exception{ 30 | //Begin the Content stream 31 | overContent.beginText(); 32 | 33 | if (null == txt) { 34 | txt = def; 35 | } 36 | 37 | //Setting the position for the line 38 | overContent.newLineAtOffset(x, y); 39 | 40 | //Adding text in the form of string 41 | overContent.showText(txt); 42 | 43 | //Ending the content stream 44 | overContent.endText(); 45 | } 46 | 47 | /** 48 | * 增加一段文本 49 | * @param contentStream 50 | * @param width 51 | * @param sx 52 | * @param sy 53 | * @param text 54 | * @param justify 55 | * @throws IOException 56 | */ 57 | private static void addParagraph(PDPageContentStream contentStream, float width, float sx, 58 | float sy, String text, boolean justify) throws IOException { 59 | List lines = new ArrayList<>(); 60 | parseLinesRecursive(text, width, lines); 61 | 62 | contentStream.setFont(FONT, FONT_SIZE); 63 | contentStream.newLineAtOffset(sx, sy); 64 | for (String line: lines) { 65 | float charSpacing = 0; 66 | if (justify){ 67 | if (line.length() > 1) { 68 | float size = FONT_SIZE * FONT.getStringWidth(line) / 1000; 69 | float free = width - size; 70 | if (free > 0 && !lines.get(lines.size() - 1).equals(line)) { 71 | charSpacing = free / (line.length() - 1); 72 | } 73 | } 74 | } 75 | contentStream.setCharacterSpacing(charSpacing); 76 | contentStream.showText(line); 77 | contentStream.newLineAtOffset(0, LEADING); 78 | } 79 | } 80 | 81 | /** 82 | * 递归分析文本,并按宽度分割成N行 83 | * @param text 84 | * @param width 85 | * @param lines 86 | * @return 87 | * @throws IOException 88 | */ 89 | private static List parseLinesRecursive(String text, float width, List lines) throws IOException { 90 | String tmpText = text; 91 | for (int i=0; i width) { 97 | continue; 98 | } else { 99 | lines.add(tmpText); 100 | 101 | if (0 != i) { 102 | parseLinesRecursive(text.substring(text.length() - i), width, lines); 103 | } 104 | 105 | break; 106 | } 107 | } 108 | 109 | return lines; 110 | } 111 | 112 | public static void main( String[] args ) throws Exception { 113 | try { 114 | // Loading an existing document 115 | InputStream in = PDFBoxDemo.class.getClassLoader().getResourceAsStream("VAT_INVOICE.pdf"); 116 | PDDocument document = PDDocument.load(in); 117 | 118 | // Retrieving the pages of the document, and using PREPEND mode 119 | PDPage page = document.getPage(0); 120 | PDPageContentStream contentStream = new PDPageContentStream(document, page, 121 | PDPageContentStream.AppendMode.PREPEND, false); 122 | 123 | InputStream inFont = PDFBoxDemo.class.getClassLoader().getResourceAsStream("simfang.ttf"); 124 | PDType0Font font = PDType0Font.load(document, inFont); 125 | FONT = font; 126 | 127 | // Setting the font to the Content stream 128 | contentStream.setFont(font, 10); 129 | 130 | // 发票代码 131 | showTextByLeft(contentStream, "000000000211", "", 475,365); 132 | // 发票号码 133 | showTextByLeft(contentStream, "00000833", "", 475,350); 134 | // 开票日期 135 | showTextByLeft(contentStream, "2018年12月19日", "", 475,335); 136 | // 校验码 137 | showTextByLeft(contentStream, "12345 34567 56789 78901", "", 475,318); 138 | 139 | // 机器编号 140 | showTextByLeft(contentStream, "499098894300", "", 65,318); 141 | 142 | // 购买方 名称 143 | showTextByLeft(contentStream, "新龙门连锁客栈(上海)有限公司", "", 108,303); 144 | // 购买方 纳税人识别号 145 | showTextByLeft(contentStream, "95270000710929885W", "", 108,290); 146 | // 购买方 地址、电话 147 | showTextByLeft(contentStream, "上海万宝路大前门1234号 021-000000001", "", 108,275); 148 | 149 | // 备注 显示成多行 150 | String text = "增值税专用发票是由国家税务总局监制设计印制的,ABCDEFGHIJKLMNOPQRSTUVWXYZ只限于增值税一般纳税人领购使用的,作为纳税人反映经济活动中的重要会计凭证。" ; 151 | contentStream.beginText(); 152 | addParagraph(contentStream, 200, 380, 95, text, true); 153 | contentStream.endText(); 154 | 155 | // 开票人 156 | showTextByLeft(contentStream, "老张", "", 355,33); 157 | 158 | System.out.println("Content added"); 159 | 160 | // Adding watermark 161 | for(PDPage everyPage:document.getPages()){ 162 | PDPageContentStream cs = new PDPageContentStream(document, everyPage, PDPageContentStream.AppendMode.APPEND, 163 | true, true); 164 | String ts = "测试"; 165 | float fontSize = 80.0f; 166 | PDExtendedGraphicsState r0 = new PDExtendedGraphicsState(); 167 | // 透明度 168 | r0.setNonStrokingAlphaConstant(0.3f); 169 | r0.setAlphaSourceFlag(true); 170 | 171 | cs.setGraphicsStateParameters(r0); 172 | cs.setNonStrokingColor(188,188,188); 173 | cs.beginText(); 174 | cs.setFont(font, fontSize); 175 | // 获取旋转实例 176 | cs.setTextMatrix(Matrix.getRotateInstance(45,320f,150f)); 177 | cs.showText(ts); 178 | cs.endText(); 179 | 180 | cs.close(); 181 | } 182 | 183 | // Loading img from file 184 | PDImageXObject pdImage = PDImageXObject.createFromFile("src/main/resources/song.png", document); 185 | 186 | // Draw image by x y width height 187 | contentStream.drawImage(pdImage, 480, 10, 100, 100); 188 | 189 | // Closing the content stream 190 | contentStream.close(); 191 | 192 | // Saving the document 193 | document.save(new File("..\\new_VAT_INVOICE.pdf")); 194 | 195 | // Closing the document 196 | document.close(); 197 | } catch (Exception e) { 198 | // TODO Auto-generated catch block 199 | e.printStackTrace(); 200 | } 201 | } 202 | 203 | } 204 | --------------------------------------------------------------------------------