java操作pdf>>>pdfBox使用体验

xiaoxiao2021-02-28  66

pdfBox对中文非常不友好,如果各位同学最进要对pdf进行插入文字操作的话,建议你们使用itext,如果你操作的pdf没有中文,或者只是对pdf文件插入图片,删除页面等操作,那么请继续看下去~~~~

前言:

前段时间在完成公司安排的任务同时,利用空余时间做了一个使用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; }

—–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; }

pdfbox很强大,最主要是开源,(就是TMD不支持中文)以上只是部分功能,大家如果还想拓展,可以参考官方的事例和api

PS:遗憾的是,我没有处理好,替换文字或者是插入文字时,中文乱码问题,有处理好的同学记得和博主说一下,大家共同进步

这有一篇文:http://blog.csdn.net/undergrowth/article/details/39136673是对于pdfbox各个方法,属性解析的比较好的文,大家可以去看下

转载请注明原文地址: https://www.6miu.com/read-83396.html

最新回复(0)