Java使用PDFBox操作PDF檔案
阿新 • • 發佈:2018-12-31
前言:
前段時間在完成公司安排的任務同時,利用空餘時間做了一個使用java操作pdf的功能
剛開始沒什麼頭緒,直到在網上找到了pdfBox,
pdfBox是apach提供的免費,開源的pdf操作工具,使用起來也挺方便,github可下載
我也上傳了一份, [ pdfbox-1.8.9.zip ]
1首先,匯入jar
我是maven方式匯入
PS:
這個jar裡面囊括了所有的pdfbox操作工具類,匯入這一個就夠了
(我在找工具類的時候,看到別的博主導了pdfbox的很多類,然後一股腦也導了進去,結果jar包衝突,原來只匯入一個,那就是官方已經整合好的那個,就夠了)
< dependency>
<groupId>org.apache.pdfbox</groupId>
<artifactId>pdfbox-app</artifactId>
<version>1.8.10</version>
</dependency>
2.在你的專案中建立一個工具類
2.1這個類的取名:隨意,
我是取的pdfUtil
2.2當然,如果你想將操作記錄入錄到資料庫的話,你也可以建立一個pdf的實體類
這個實體類創不建立大家隨意,我貼一下我的實體類的屬性,供參考
//實體類的名稱:pdfDomainVO
private Integer id;//id
private Date time;//操作時間
private String filename;//檔名
private String filesize;//檔案大小
private String filetype;//檔案型別
private String details;//操作詳情
private String content;//pdf中內容
private String outputfile;//輸出路徑(儲存路徑)
private String inputfile;//要操作的pdf路徑
private String strtofind;//需要替換的文字
private String message;//替換的文字
private String imagefile;//圖片路徑
private String imagelist;//圖片集合
private Integer pageno;//指定頁碼
private Integer pages;//總頁數
private Integer rid;//...
private Integer pageoperation;//操作頁數
private Integer pagestart;//開始頁
private Integer pageend;//結束頁
private String position;//位置:X,Y
private String fileSizeAfter;//操作後文件大小
private Integer status;//狀態
private Integer afterPages;//操作後頁碼
private Integer imgSize;//圖片大小
3.在pdfUtil寫程式碼
PS:我下面會有用到pdfDomainVO實體類的時候,大家參考下上面貼的屬性
- 大家可以在pdfbox-1.8.9.zip資料夾中,找到examples資料夾
- 裡面有很多事例,比如:
- 1建立一個pdf檔案
- 2讀取pdf中,全部文字資訊(可用String接收)
- 3替換pdf中字元(中文我還沒有解決好,不好意思啊)
- 4在pdf中插入圖片
- 等等操作……
PS:我現在貼一下我的程式碼
—–1建立1到多個空白頁面
/***
* 建立1到多個空白頁面
* @param file
* @throws IOException
* @throws COSVisitorException
*/
public static void createBlank( String outputFile ) throws IOException, COSVisitorException
{
//首先建立pdf文件類
PDDocument document = null;
try
{
document = new PDDocument();
//例項化pdf頁物件
PDPage blankPage = new PDPage();
PDPage blankPage1 = new PDPage();
PDPage blankPage2 = new PDPage();
//插入文件類
document.addPage( blankPage );
document.addPage( blankPage1 );
document.addPage( blankPage2 );
//記得一定要寫儲存路徑,如"H:\\text.pdf"
document.save( outputFile );
System.out.println("over");
}
finally
{
if( document != null )
{
document.close();
}
}
}
—–2讀取pdf中文字資訊(全部)
/**
* 讀取pdf中文字資訊(全部)
*/
public static void READPDF(String inputFile){
//建立文件物件
PDDocument doc =null;
String content="";
try {
//載入一個pdf物件
doc =PDDocument.load(new File(inputFile));
//獲取一個PDFTextStripper文字剝離物件
PDFTextStripper textStripper =new PDFTextStripper("GBK");
content=textStripper.getText(doc);
vo.setContent(content);
System.out.println("內容:"+content);
System.out.println("全部頁數"+doc.getNumberOfPages());
//關閉文件
doc.close();
} catch (Exception e) {
// TODO: handle exception
}
}
—–3讀取pdf中文字資訊(指定頁面)
/**
* 讀取pdf中文字資訊(指定從第幾頁開始)
*/
public static pdfDomainVO readPageNO(pdfDomainVO vo){
String content="";
try{
PDDocument document = PDDocument.load(vo.getInputfile());
// 獲取頁碼
int pages = document.getNumberOfPages();
// 讀文字內容
PDFTextStripper stripper=new PDFTextStripper();
// 設定按順序輸出
stripper.setSortByPosition(true);
stripper.setStartPage(vo.getPageno());
stripper.setEndPage(vo.getPageno());
//獲取內容
content = stripper.getText(document);
vo.setContent(content);
System.out.println("function : readPageNO over");
} catch (Exception e) {
e.printStackTrace();
}
return vo;
}
—–4替換指定pdf檔案的文字內容(這個比較複雜,當時看api看了好久,然後一個一個的吧註釋添了上去)
/**
* 替換指定pdf檔案的文字內容
* @param args
*/
public static pdfDomainVO replaceContent(pdfDomainVO vo)
throws IOException,COSVisitorException{
//建立一個文件物件
PDDocument doc =null;
try {
//載入檔案
doc =PDDocument.load(vo.getInputfile());
//獲取全部頁數
List pages= doc.getDocumentCatalog().getAllPages();
//獲取與i對應的頁面
PDPage page = (PDPage)pages.get( vo.getPageno() );
//流物件來接收當前page的內容
PDStream contents = page.getContents();
//PDF流物件剖析器(這將解析一個PDF位元組流並提取運算元,等等)
PDFStreamParser parser =new PDFStreamParser(contents.getStream());
//這將分析流中的標記
parser.parse();
//用list存流中的所有標記
List tokens =parser.getTokens();
for (int j = 0; j < tokens.size(); j++) {
//建立一個object物件去接收標記
Object next = tokens.get( j );
//instanceof判斷其左邊物件是否為其右邊類的例項
if(next instanceof PDFOperator ) {
//pdf操作器物件
PDFOperator op =(PDFOperator)next;
//TJ和TJ是顯示的兩個操作符。
//PDF中的字串
if(op.getOperation().equals("Tj")){
//COSString物件>>建立java字串的一個新的文字字串。
COSString previous = (COSString)tokens.get( j-1 );
//將此字串的內容作為PDF文字字串返回。
String string=previous.getString();
//replaceFirst>>替換第一個字元
string = string.replaceFirst( vo.getStrtofind(), vo.getMessage() );
System.out.println(string);
System.out.println(string.getBytes("GBK"));
//重置COSString物件
previous.reset();
//設定字元編碼格式
previous.append(string.getBytes("GBK") );
}else if(op.getOperation().equals("TJ")){
//COSArray是pdfbase物件陣列,作為PDF文件的一部分
COSArray previous =(COSArray)tokens.get( j-1 );
//迴圈previous
for (int k = 0; k < previous.size(); k++) {
//這將從陣列中獲取一個物件,這將取消引用該物件
//如果物件為cosnull,則返回null
Object arrElement = previous.getObject( k );
if( arrElement instanceof COSString ){
//COSString物件>>建立java字串的一個新的文字字串。
COSString cosString =(COSString)arrElement;
//將此字串的內容作為PDF文字字串返回。
String string =cosString.getString();
//替換
string = string.replaceFirst( vo.getStrtofind(), vo.getMessage());
//重置COSString物件
cosString.reset();
//設定字元編碼格式
cosString.append(string.getBytes("GBK") );
}
}
}
}
}
//建立一個PDStream 流物件
PDStream updatedStream = new PDStream(doc);
//建立一個輸出流接收updatedStream
OutputStream out =updatedStream.createOutputStream();
//將接受一個列表並寫出它們的流。
ContentStreamWriter tokenWriter =new ContentStreamWriter(out);
//寫入一系列標記,後面跟著一行新行
tokenWriter.writeTokens(tokens);
//當前頁設定新的內容
page.setContents( updatedStream );
//修改後儲存的路徑
doc.save(vo.getOutputfile());
//操作後的頁數
vo.setAfterPages(doc.getNumberOfPages());
} catch (Exception e) {
e.printStackTrace();
}finally{
if( doc != null ){
//關閉文件
doc.close();
}
}
return vo;
}
—–5在pdf中插入圖片(按指定頁數插入)
/**
* 在pdf中插入圖片
* @param inputFile
* @param image
* @param outputFile
* @throws IOException
* @throws COSVisitorException
*/
public static pdfDomainVO insertImage( pdfDomainVO vo )
throws IOException, COSVisitorException{
//偏移量設定
String[] position =vo.getPosition().split(",");
int x =Integer.valueOf(position[0]);
int y =Integer.valueOf(position[position.length-1]);
//建立一個文件物件
PDDocument doc =null;
try {
//載入
doc = PDDocument.load(vo.getInputfile());
//獲取載入進來的pdf檔案的頁面
PDPage page = (PDPage)doc.getDocumentCatalog().getAllPages().get( vo.getPageno() );
//pdfbox中圖片物件類
PDXObjectImage ximage = null;
//判斷是否是.jpg格式的圖片
if( vo.getImagefile().toLowerCase().endsWith( ".jpg" ) ){
//傳入一張圖片
ximage = new PDJpeg(doc, new FileInputStream( vo.getImagefile() ) );
}//如果是tif或tiff格式
else if (vo.getImagefile().toLowerCase().endsWith(".tif") || vo.getImagefile().toLowerCase().endsWith(".tiff")){
ximage = new PDCcitt(doc, new RandomAccessFile(new File(vo.getImagefile()),"r"));
}else{
//Image和BufferedImage的主要作用就是將一副圖片載入到記憶體中
BufferedImage awtImage = ImageIO.read( new File( vo.getImagefile() ) );
ximage = new PDPixelMap(doc, awtImage);
}
//這是選擇如何處理流:覆蓋、追加
PDPageContentStream contentStream = new PDPageContentStream(doc, page, true, true);
//控制圖片的大小
float scale = vo.getImgSize();
scale = scale/10;//(這個值最好是0.1~1,0.5就已經很大了)
//ximage.setHeight(ximage.getHeight()/5);
//ximage.setWidth(ximage.getWidth()/5);
System.out.println(ximage.getHeight());
System.out.println(ximage.getWidth());
//設定位移等引數
contentStream.drawXObject(ximage, x, y, ximage.getWidth()*scale, ximage.getHeight()*scale);
//關閉流物件
contentStream.close();
//儲存路徑
doc.save( vo.getOutputfile() );
//操作後的頁數
vo.setAfterPages(doc.getNumberOfPages());
} catch (Exception e) {
e.printStackTrace();
}finally{
if( doc != null ){
//關閉文件
doc.close();
}
}
return vo;
}
—–6指定頁數的PDF檔案轉換為圖片
/***
* 指定頁數的PDF檔案轉換為圖片:
* @param inputFile
* @param outputFile 這裡指定資料夾
*/
public static pdfDomainVO toImage( pdfDomainVO vo ) {
try {
//載入
PDDocument doc = PDDocument.load(vo.getInputfile());
//
//int pageCount = doc.getPageCount();
////獲取全部頁數
//指定單頁轉pdf
List pages = doc.getDocumentCatalog().getAllPages();
if(vo.getPageno()!=null){
String count=(int)(Math.random()*1000)+"-"+(int)(Math.random()*1000);
//接收頁面
PDPage page = (PDPage) pages.get(vo.getPageno());
//定義圖片操作物件來設定圖片
BufferedImage image = page.convertToImage();
//定義迭代器物件儲存
Iterator iter = ImageIO.getImageWritersBySuffix("jpg");
//圖片寫入器物件寫入圖片
ImageWriter writer = (ImageWriter) iter.next();
//迴圈儲存圖片
File outFile = new File(vo.getOutputfile()+vo.getFilename()+"-"+(vo.getPageno()+1)+".jpg");
//建立檔案輸出流物件
FileOutputStream out = new FileOutputStream(outFile);
//ImageIO去實現ImageOutputStream獲取當前圖片
ImageOutputStream outImage = ImageIO.createImageOutputStream(out);
writer.setOutput(outImage);
writer.write(new IIOImage(image, null, null));
}else{
//迴圈
for (int i = 0; i < pages.size(); i++) {
//接收頁面
PDPage page = (PDPage) pages.get(i);
//定義圖片操作物件來設定圖片
BufferedImage image = page.convertToImage();
//定義迭代器物件儲存
Iterator iter = ImageIO.getImageWritersBySuffix("jpg");
//圖片寫入器物件寫入圖片
ImageWriter writer = (ImageWriter) iter.next();
//迴圈儲存圖片
File outFile = new File(vo.getOutputfile()+i+".jpg");
//建立檔案輸出流物件
FileOutputStream out = new FileOutputStream(outFile);
//ImageIO去實現ImageOutputStream獲取當前圖片
ImageOutputStream outImage = ImageIO.createImageOutputStream(out);
writer.setOutput(outImage);
writer.write(new IIOImage(image, null, null));
}
}
//關文件
doc.close();
//操作後的頁數
vo.setAfterPages(doc.getNumberOfPages());
System.out.println("over");
} catch (Exception e) {
e.printStackTrace();
}
return vo;
}
—–7指定頁插入一段文字(大家可自調字型,插入文字的位置)
/***
* 指定頁插入一段文字
* @param inputFile
* @param message
* @param outputFile
* @throws IOException
* @throws COSVisitorException
*/
public static pdfDomainVO InsertPageContent (pdfDomainVO vo ) throws IOException, COSVisitorException
{
// the document
PDDocument doc = null;
try
{
doc = PDDocument.load( vo.getInputfile() );
List allPages = doc.getDocumentCatalog().getAllPages();
PDFont font = PDType1Font.HELVETICA_BOLD;
//字型大小
float fontSize = 36.0f;
PDPage page = (PDPage)allPages.get( vo.getPageno() );
PDRectangle pageSize = page.findMediaBox();
float stringWidth = font.getStringWidth( vo.getMessage() )*fontSize/1000f;
// calculate to center of the page
int rotation = page.findRotation();
boolean rotate = rotation == 90 || rotation == 270;
float pageWidth = rotate ? pageSize.getHeight() : pageSize.getWidth();
float pageHeight = rotate ? pageSize.getWidth() : pageSize.getHeight();
double centeredXPosition = rotate ? pageHeight/2f : (pageWidth - stringWidth)/2f;
double centeredYPosition = rotate ? (pageWidth - stringWidth)/2f : pageHeight/2f;
// append the content to the existing stream
PDPageContentStream contentStream = new PDPageContentStream(doc, page, true, true,true);
contentStream.beginText();
// set font and font size
contentStream.setFont( font, fontSize );
// set text color to red
contentStream.setNonStrokingColor(255, 0, 0);
if (rotate)
{
// rotate the text according to the page rotation
contentStream.setTextRotation(Math.PI/2, centeredXPosition, centeredYPosition);
}
else
{
contentStream.setTextTranslation(centeredXPosition, centeredYPosition);
}
contentStream.drawString( vo.getMessage() );
contentStream.endText();
contentStream.close();
vo.setAfterPages(doc.getNumberOfPages());
doc.save( vo.getOutputfile() );
System.out.println("over");
}
finally
{
if( doc != null )
{
doc.close();
}
}
return vo;
}
—–8提取圖片並儲存
/**
* 提取圖片並儲存
* @param pdfDomainVO
* @throws IOException
*
*/
public static pdfDomainVO extractImage(pdfDomainVO vo ) throws IOException{
//建立文件
PDDocument doc=null;
try{
//載入 pdf 文件,獲取PDDocument文件物件
doc=PDDocument.load(vo.getInputfile());
/** 文件頁面資訊 **/
//獲取PDDocumentCatalog文件目錄物件
PDDocumentCatalog catalog = doc.getDocumentCatalog();
//獲取文件頁面PDPage列表
List pages = catalog.getAllPages();
int pageNum=pages.size(); //文件頁數
PDPage page = null;
if(vo.getPageno()!=null){
page = ( PDPage ) pages.get( vo.getPageno() );
if( null != page ){
PDResources resource = page.findResources();
//獲取頁面圖片資訊
Map<String,PDXObjectImage> imgs = resource.getImages();
for(Map.Entry<String,PDXObjectImage> me: imgs.entrySet()){
//System.out.println(me.getKey());
PDXObjectImage img = me.getValue();
//儲存圖片,會自動新增圖片字尾型別
img.write2file( vo.getOutputfile() + vo.getFilename()+"-"+(vo.getPageno()+1) );
}
}
}else{
//遍歷每一頁
for( int i = 0; i < pageNum; i++ ){
//取得第i頁
page = ( PDPage ) pages.get( i );
if( null != page ){
PDResources resource = page.findResources();
//獲取頁面圖片資訊
Map<String,PDXObjectImage> imgs = resource.getImages();
for(Map.Entry<String,PDXObjectImage> me: imgs.entrySet()){
String count=(int)(Math.random()*1000)+"-"+(int)(Math.random()*1000);
//System.out.println(me.getKey());
PDXObjectImage img = me.getValue();
//儲存圖片,會自動新增圖片字尾型別
img.write2file( vo.getOutputfile() + count );
}
}
}
}
//操作後的頁數
vo.setAfterPages(doc.getNumberOfPages());
System.out.println("extractImage:over");
} finally
{
if( doc != null )
{
doc.close();
}
}
return vo;
}
- /ul>
—–9PDF文件中刪除頁面(不能刪除最後一頁!)
/***
* PDF文件中刪除頁面
* 一個PDF文件必須至少有一頁,且不能刪除最後一頁!
* @param inputFile
* @param outputFile
* @throws Exception
*/
public static pdfDomainVO removePage(pdfDomainVO vo) throws Exception
{
vo.setStatus(Details.FailStatus);
PDDocument document = null;
try
{
document = PDDocument.load(vo.getInputfile() );
if( document.isEncrypted() )
{
throw new IOException( "Encrypted documents are not supported for this example" );
}
if( document.getNumberOfPages() <= 1 )
{
throw new IOException( "Error: A PDF document must have at least one page, " +
"cannot remove the last page!");
}
document.removePage( vo.getPageno() );
document.save(vo.getOutputfile() );
//操作後的頁數
vo.setAfterPages(document.getNumberOfPages());
//設定成功狀態
vo.setStatus(Details.SuccessStatus);
System.out.println("over");
}
finally
{
if( document != null )
{
document.close();
}
}
return vo;
}