在实际的开发过程中,可能会遇到以下的一些场景:
- 一个全部为竖版的PDF文件,现在需要将其全部转换为横版PDF文件;
- 一个全部为竖版的PDF文件,现在需要将指定页转换为横版PDF文件;
- 一个PDF文件中既有横板也有竖版,现在需要将所有横版转换为竖版;
- 一个PDF文件中既有横板也有竖版,现在需要将所有竖版转换为横版;
这些需求都可以通过使用 itextpdf
开源库来实现,下面来通过代码进行演示。
需要说明的是,这里的转换只是PDF版式的旋转,并非是页面内容的旋转,如果需要在旋转版式的时候,同时旋转页面上的文字,那么下面的方法可能不太适用了。
1、引入依赖
目前 itextpdf
最新版本为 5.5.13.3
,可以在 https://search.maven.org/ 网站进行搜索。
com.itextpdf
itextpdf
5.5.13.3
2、代码实现
不论是横版PDF转竖版PDF,还是竖版PDF转横板PDF,其实都是旋转问题,比如将一个横版PDF顺时针或者逆时针旋转90,得到的就是一个竖版的PDF,而将一个竖版PDF顺时针或者逆时针旋转90,得到的就是一个横板的PDF。
package com.magic.itextpdf;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.List;
import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.pdf.PdfCopy;
import com.itextpdf.text.pdf.PdfDictionary;
import com.itextpdf.text.pdf.PdfName;
import com.itextpdf.text.pdf.PdfNumber;
import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.PdfSmartCopy;
/**
* PDF工具类
*/
public class PdfUtils {
/**
* 旋转PDF文件
* @param sourceFile 源PDF文件路径
* @param targetFile 目标PDF文件路径
* @param angle 旋转角度
*/
public static void rotate(String sourceFile, String targetFile, int angle) {
PdfReader reader = null;
Document document = null;
FileOutputStream outputStream = null;
try {
// 读取源文件
reader = new PdfReader(sourceFile);
// 创建新的文档
document = new Document();
// 创建目标PDF文件
outputStream = new FileOutputStream(targetFile);
PdfCopy pdfCopy = new PdfSmartCopy(document, outputStream);
// 获取源文件的页数
int pages = reader.getNumberOfPages();
document.open();
PdfDictionary pdfDictionary;
// 注意此处的页码是从1开始
for (int page = 1; page <= pages; page++) {
pdfDictionary = reader.getPageN(page);
pdfDictionary.put(PdfName.ROTATE, new PdfNumber(angle));
pdfCopy.addPage(pdfCopy.getImportedPage(reader, page));
}
} catch (IOException | DocumentException e) {
e.printStackTrace();
} finally {
if (reader != null) {
reader.close();
}
if (document != null) {
document.close();
}
if (outputStream != null) {
try {
outputStream.flush();
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
这里的旋转角度 angle
必须是90的倍数,如果是其他的角度,则是无效的。有了旋转的方法后,我们可以再定义一些基础方法,比如顺时针旋转(右旋转)、逆时针旋转(左旋转)和垂直翻转,这样使用起来会更加方便。
(1)顺时针旋转(右旋转90)
/**
* 右旋转PDF文件90度
* @param sourceFile 源PDF文件路径
* @param targetFile 目标PDF文件路径
*/
public static void rightRotate(String sourceFile, String targetFile) {
rotate(sourceFile, targetFile, -90);
}
(2)逆时针旋转(左旋转90)
/**
* 左旋转PDF文件90度
* @param sourceFile 源PDF文件路径
* @param targetFile 目标PDF文件路径
*/
public static void leftRotate(String sourceFile, String targetFile) {
rotate(sourceFile, targetFile, 90);
}
(3)垂直(旋转180)
/**
* 翻转PDF文件
* @param sourceFile 源PDF文件路径
* @param targetFile 目标PDF文件路径
*/
public static void filp(String sourceFile, String targetFile) {
rotate(sourceFile, targetFile, 180);
}
在某些固定的场景下,可能旋转就是特指逆时针旋转,那么这个时候,我们还可以重载 rotate()
方法,默认使用 leftRotate()
方法,如下:
/**
* 旋转PDF文件
* @param sourceFile 源PDF文件路径
* @param targetFile 目标PDF文件路径
*/
public static void rotate(String sourceFile, String targetFile) {
leftRotate(sourceFile, targetFile);
}
3、指定页面旋转
上面的实现是将所有的PDF文件都旋转,但是有的时候,可能只想旋转指定的页码,而其余的保持不变,可以采用重载 rotate()
方法来实现指定页码旋转。
/**
* 旋转PDF文件
* @param sourceFile 源PDF文件路径
* @param targetFile 目标PDF文件路径
* @param angle 旋转角度
* @param rotatedPageNums 需要旋转的页码
*/
public static void rotate(String sourceFile, String targetFile, int angle, List rotatedPageNums) {
PdfReader reader = null;
Document document = null;
FileOutputStream outputStream = null;
try {
// 读取源文件
reader = new PdfReader(sourceFile);
// 创建新的文档
document = new Document();
// 创建目标PDF文件
outputStream = new FileOutputStream(targetFile);
PdfCopy pdfCopy = new PdfSmartCopy(document, outputStream);
// 获取源文件的页数
int pages = reader.getNumberOfPages();
document.open();
PdfDictionary pdfDictionary;
// 注意此处的页码是从1开始
for (int page = 1; page <= pages; page++) {
pdfDictionary = reader.getPageN(page);
if (null == rotatedPageNums || rotatedPageNums.isEmpty()) {
pdfDictionary.put(PdfName.ROTATE, new PdfNumber(angle));
} else if (rotatedPageNums.contains(page)) {
pdfDictionary.put(PdfName.ROTATE, new PdfNumber(angle));
}
pdfCopy.addPage(pdfCopy.getImportedPage(reader, page));
}
} catch (IOException | DocumentException e) {
e.printStackTrace();
} finally {
if (reader != null) {
reader.close();
}
if (document != null) {
document.close();
}
if (outputStream != null) {
try {
outputStream.flush();
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
这个方法多了一个参数 List
,传递的是需要旋转的页码,比如说需要旋转1、3、5页,那么可以这样调用:
PdfUtils.rotate("D:\\Test\\test.pdf", "D:\\Test\\test_out.pdf", 90, Arrays.asList(1, 3, 5));
如果连续旋转某些页面,比如从10-60,如果使用上面的方法调用的话,那么参数就比较多了,这个时候,又可以重载一个方法,来根据起始页码和结束页码实现旋转,具体代码如下:
/**
* 旋转PDF文件
* @param sourceFile 源PDF文件路径
* @param targetFile 目标PDF文件路径
* @param angle 旋转角度
* @param fromPageNum 起始页码
* @param toPageNum 结束页码
*/
public static void rotate(String sourceFile, String targetFile, int angle, int fromPageNum, int toPageNum) {
PdfReader reader = null;
Document document = null;
FileOutputStream outputStream = null;
try {
// 读取源文件
reader = new PdfReader(sourceFile);
// 创建新的文档
document = new Document();
// 创建目标PDF文件
outputStream = new FileOutputStream(targetFile);
PdfCopy pdfCopy = new PdfSmartCopy(document, outputStream);
// 获取源文件的页数
int pages = reader.getNumberOfPages();
document.open();
PdfDictionary pdfDictionary;
// 注意此处的页码是从1开始
for (int page = 1; page <= pages; page++) {
pdfDictionary = reader.getPageN(page);
// 如果页面是在起始页码和结束页码之间的,则进行旋转
if (page >= fromPageNum && page <= toPageNum) {
pdfDictionary.put(PdfName.ROTATE, new PdfNumber(angle));
}
pdfCopy.addPage(pdfCopy.getImportedPage(reader, page));
}
} catch (IOException | DocumentException e) {
e.printStackTrace();
} finally {
if (reader != null) {
reader.close();
}
if (document != null) {
document.close();
}
if (outputStream != null) {
try {
outputStream.flush();
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
此时就可以根据起始结束页码来旋转了,如下:
PdfUtils.rotate("D:\\Test\\test.pdf", "D:\\Test\\test_out.pdf", 90, 10, 60);
4、旋转所有横版
假如一个PDF文件中既有横版,又有竖版,这个时候希望把所有的横版都转换为竖版,上面已有的方法是满足不了的,可以定义新的方法,如下:
/**
* 旋转PDF文件中的所有横版
* @param sourceFile 源PDF文件路径
* @param targetFile 目标PDF文件路径
* @param angle 旋转角度
*/
public static void rotateHorizontal(String sourceFile, String targetFile, int angle) {
PdfReader reader = null;
Document document = null;
FileOutputStream outputStream = null;
try {
// 读取源文件
reader = new PdfReader(sourceFile);
// 创建新的文档
document = new Document();
// 创建目标PDF文件
outputStream = new FileOutputStream(targetFile);
PdfCopy pdfCopy = new PdfSmartCopy(document, outputStream);
// 获取源文件的页数
int pages = reader.getNumberOfPages();
document.open();
PdfDictionary pdfDictionary;
// 注意此处的页码是从1开始
for (int page = 1; page <= pages; page++) {
pdfDictionary = reader.getPageN(page);
// 根据页面的宽度
float pageWidth = reader.getPageSize(page).getWidth();
if (pageWidth > 600F) {
pdfDictionary.put(PdfName.ROTATE, new PdfNumber(angle));
}
pdfCopy.addPage(pdfCopy.getImportedPage(reader, page));
}
} catch (IOException | DocumentException e) {
e.printStackTrace();
} finally {
if (reader != null) {
reader.close();
}
if (document != null) {
document.close();
}
if (outputStream != null) {
try {
outputStream.flush();
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
旋转所有的横版,是根据页面的宽度进行,横版的宽度比竖版的宽,而对于横版A4版面PDF文件,其宽高分别为841.9和595.3。
5、旋转所有竖版
上面实现了旋转所有的横版,同理,可能也会遇到需要旋转所有的竖版的需求,代码如下:
/**
* 旋转PDF文件中的所有竖版
* @param sourceFile 源PDF文件路径
* @param targetFile 目标PDF文件路径
* @param angle 旋转角度
*/
public static void rotateVertical(String sourceFile, String targetFile, int angle) {
PdfReader reader = null;
Document document = null;
FileOutputStream outputStream = null;
try {
// 读取源文件
reader = new PdfReader(sourceFile);
// 创建新的文档
document = new Document();
// 创建目标PDF文件
outputStream = new FileOutputStream(targetFile);
PdfCopy pdfCopy = new PdfSmartCopy(document, outputStream);
// 获取源文件的页数
int pages = reader.getNumberOfPages();
document.open();
PdfDictionary pdfDictionary;
// 注意此处的页码是从1开始
for (int page = 1; page <= pages; page++) {
pdfDictionary = reader.getPageN(page);
// 根据页面的高度
float pageHeight = reader.getPageSize(page).getHeight();
if (pageHeight > 600F) {
pdfDictionary.put(PdfName.ROTATE, new PdfNumber(angle));
}
pdfCopy.addPage(pdfCopy.getImportedPage(reader, page));
}
} catch (IOException | DocumentException e) {
e.printStackTrace();
} finally {
if (reader != null) {
reader.close();
}
if (document != null) {
document.close();
}
if (outputStream != null) {
try {
outputStream.flush();
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
如果一个PDF文件同时存在A4横版和A4竖版,那么竖版的高度比横版的高,并且竖版的高度值为横版的宽度,这个时候横竖版的宽高分别如下:
- 横版:841.9 x 595.3
- 竖版:595.3 x 841.9
6、测试验证
现在使用上面的旋转方法把一个PDF中的第2页转换为竖版,测试代码如下:
package com.magic.itextpdf;
import java.util.Collections;
public class Test {
public static void main(String[] args) {
PdfUtils.rotate("D:\\Test\\test.pdf", "D:\\Test\\test_2.pdf", 90, 2, 2);
}
}
原始PDF和转换后的PDF对比如下: