導讀:近期要做一個根據關鍵字定位pdf的蓋章位置的相關需求,其中關鍵字可配置多個(包含pdf文檔中可能不存在的關鍵字),當頁面顯示蓋章完成時,打開pdf顯示已經損壞。
排查后發現,當itext搜索的關鍵字在pdf文檔中不存在時,就已經將結果返回到前台界面,這時itex讀取的流還未關閉,導致pdf讀取未結束,pdf文檔才被損壞。
下面是讀取pdf的操作,記錄一下:
所需包: itext-2.06.jar itext-asian,jar itextpdf-5.4.0.jar
/****搜索關鍵字操作:****/ /*sourcePDF: pdf的文檔路徑 splitParentkeyValues[i]:關鍵字,其中對關鍵字進行特殊符號的過濾,不然會導致后面的匹配結果有誤。*/ matches = MatchItemUtil.matchPage(sourcePDF, splitParentkeyValues[i]); /*找出關鍵字后,將要蓋章的圖片准確定位到關鍵字周圍,也可以采用坐標的方式**/ MatchItem matchItem = new MatchItem(); int pageNum = matches.get(j).getPageNum(); float pageWidth = reader.getPageSize(pageNum).getWidth(); float pageHeight = reader.getPageSize(pageNum).getHeight(); matchItem.setX(matches.get(j).getX()-splitParentkeyValues.length * 20); matchItem.setY(matches.get(j).getY() - 150 / 1.527731f); img.setAbsolutePosition(matchItem.getX(), matchItem.getY());// 位置 PdfContentByte over = stamp.getOverContent(pageNum); over.addImage(img);
1. //根據關鍵字和pdf路徑,全文搜索關鍵字
/** 查找所有 @param fileName 文件路徑 @param keyword 關鍵詞 @return @throws Exception */ public static List matchPage(String fileName,String keyword) throws Exception { List items = new ArrayList(); PdfReader reader = new PdfReader(fileName); int pageSize = reader.getNumberOfPages(); for(int page = 1;page <= pageSize;page++){ items.addAll(matchPage(reader,page,keyword)); } return items; }
2. 根據關鍵字、文檔路徑、pdf頁數尋找特定的文件內容
/** 在文件中尋找特定的文字內容 @param reader @param pageNumber @param keyword @return @throws Exception */ public static List matchPage(PdfReader reader, Integer pageNumber,String keyword) throws Exception { KeyWordPositionListener renderListener = new KeyWordPositionListener(); renderListener.setKeyword(keyword); PdfReaderContentParser parse = new PdfReaderContentParser(reader); Rectangle rectangle = reader.getPageSize(pageNumber); renderListener.setPageNumber(pageNumber); renderListener.setCurPageSize(rectangle); parse.processContent(pageNumber, renderListener); return findKeywordItems(renderListener,keyword); }
3. 找到匹配的關鍵詞塊
/** 找到匹配的關鍵詞塊 @param renderListener @param keyword @return */ public static List findKeywordItems(KeyWordPositionListener renderListener,String keyword){ //先判斷本頁中是否存在關鍵詞 List allItems = renderListener.getAllItems();//所有塊LIST StringBuffer sbtemp = new StringBuffer(“”); for(MatchItem item : allItems){//將一頁中所有的塊內容連接起來組成一個字符串。 sbtemp.append(item.getContent()); } if(sbtemp.toString().indexOf(keyword) == -1){//一頁組成的字符串沒有關鍵詞,直接return return renderListener.getMatches(); } //第一種情況:關鍵詞與塊內容完全匹配的項 List matches = renderListener.getMatches(); //第二種情況:多個塊內容拼成一個關鍵詞,則一個一個來匹配,組裝成一個關鍵詞 sbtemp = new StringBuffer(“”); List tempItems = new ArrayList(); for(MatchItem item : allItems){ //1,關鍵詞中存在某塊 2,拼裝的連續的塊=關鍵詞 3,避開某個塊完全匹配關鍵詞 //關鍵詞 中國移動 而塊為 中 ,國,移動 //關鍵詞 中華人民 而塊為中,華人民共和國 這種情況解決不了,也不允許存在 if(keyword.indexOf(item.getContent()) != -1 && !keyword.equals(item.getContent())){ tempItems.add(item); sbtemp.append(item.getContent()); if(keyword.indexOf(sbtemp.toString()) == -1){//如果暫存的字符串和關鍵詞 不再匹配時 sbtemp = new StringBuffer(item.getContent()); tempItems.clear(); tempItems.add(item); } if(sbtemp.toString().equalsIgnoreCase(keyword)){//暫存的字符串正好匹配到關鍵詞時 MatchItem tmpitem = getRightItem(tempItems, keyword); if(tmpitem != null){ matches.add(tmpitem);//得到匹配的項 } sbtemp = new StringBuffer(“”);//清空暫存的字符串 tempItems.clear();//清空暫存的LIST continue;//繼續查找 } }else{//如果找不到則清空 sbtemp = new StringBuffer(“”); tempItems.clear(); } } //第三種情況:關鍵詞存在塊中 for(MatchItem item : allItems){ if(item.getContent().indexOf(keyword) != -1 && !keyword.equals(item.getContent())){ matches.add(item); } } return matches; }
public static MatchItem getRightItem(List<MatchItem> tempItems,String keyword){ for(MatchItem item:tempItems){ if(keyword.indexOf(item.getContent()) != -1 && !keyword.equals(item.getContent())){ return item; } } return null; }
4. KeyWordPositionListener用來匹配pdf的關鍵詞
import java.util.ArrayList; import java.util.List; import org.apache.log4j.Logger; import org.drools.util.StringUtils; import com.itextpdf.awt.geom.Rectangle2D; import com.itextpdf.text.Rectangle; import com.itextpdf.text.pdf.parser.ImageRenderInfo; import com.itextpdf.text.pdf.parser.RenderListener; import com.itextpdf.text.pdf.parser.TextRenderInfo; public class KeyWordPositionListener implements RenderListener { private static Logger logger = Logger.getLogger(KeyWordPositionListener.class); private List<MatchItem> matches = new ArrayList<MatchItem>(); private List<MatchItem> allItems = new ArrayList<MatchItem>(); private Rectangle curPageSize; /** * 匹配的關鍵字 */ private String keyword; /** * 匹配的當前頁 */ private Integer pageNumber; public void beginTextBlock() { //do nothing } public void renderText(TextRenderInfo renderInfo) { String content = renderInfo.getText(); content = content.replace("<", "").replace("《", "").replace("(", "").replace("(", "").replace("\"", "").replace("'", "") .replace(">", "").replace("》", "").replace(")", "").replace(")", "").replace("、", "").replace(".", "") .replace(":", "").replace(":", "").replace(" ", ""); Rectangle2D.Float textRectangle = renderInfo.getDescentLine().getBoundingRectange(); MatchItem item = new MatchItem(); item.setContent(content); item.setPageNum(pageNumber); item.setPageWidth(curPageSize.getWidth()); item.setPageHeight(curPageSize.getHeight()); item.setX((float)textRectangle.getX()); item.setY((float)textRectangle.getY()); if(!StringUtils.isEmpty(content)){ if(content.equalsIgnoreCase(keyword)) { matches.add(item); } }else{ item.setContent("空字符串"); } allItems.add(item);//先保存所有的項 } public void endTextBlock() { //do nothing } public void renderImage(ImageRenderInfo renderInfo) { //do nothing } /** * 設置需要匹配的當前頁 * @param pageNumber */ public void setPageNumber(Integer pageNumber) { this.pageNumber = pageNumber; } /** * 設置需要匹配的關鍵字,忽略大小寫 * @param keyword */ public void setKeyword(String keyword) { this.keyword = keyword; } /** * 返回匹配的結果列表 * @return */ public List<MatchItem> getMatches() { return matches; } void setCurPageSize(Rectangle rect) { this.curPageSize = rect; } public List<MatchItem> getAllItems() { return allItems; } public void setAllItems(List<MatchItem> allItems) { this.allItems = allItems; } }
5. 用來保存關鍵字新建的對象
public class MatchItem { private Integer pageNum; private Float x; private Float y; private Float pageWidth; private Float pageHeight; private String content; public Integer getPageNum() { return pageNum; } public void setPageNum(Integer pageNum) { this.pageNum = pageNum; } public Float getX() { return x; } public void setX(Float x) { this.x = x; } public Float getY() { return y; } public void setY(Float y) { this.y = y; } public Float getPageWidth() { return pageWidth; } public void setPageWidth(Float pageWidth) { this.pageWidth = pageWidth; } public Float getPageHeight() { return pageHeight; } public void setPageHeight(Float pageHeight) { this.pageHeight = pageHeight; } public String getContent() { return content; } public void setContent(String content) { this.content = content; } public String toString() { return "MatchItem [pageNum=" + pageNum + ", x=" + x + ", y=" + y + ", pageWidth=" + pageWidth + ", pageHeight=" + pageHeight + ", content=" + content + "]"; } }