├── 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 |
--------------------------------------------------------------------------------