说明:
1、图片命名规则:给定的文件所属目录+给定的文件的名称+.+png,即同目录下同名称的png图片
2、基本业务:
a、判断同目录下同名称的png图片是否存在,若已经存在直接return
b、若png图片不存在,判断所属文件类型,除了doc/docx/ppt/pptx/pdf,其他的文件一律不处理
c、判断是doc/docx/pptx/ppt,还是pdf,若不是pdf那么调用openoffice将文件转成pdf,命名规则同图片的命名规则,后缀名:pdf
d、将pdf文件的首页内容生成图片
e、若生成的图片过大,生成缩略图
代码如下:
import java.awt.Dimension; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Image; import java.awt.Rectangle; import java.awt.Transparency; import java.awt.image.BufferedImage; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.net.ConnectException; import java.text.DecimalFormat; import java.util.Iterator; import java.util.Vector; import javax.imageio.IIOImage; import javax.imageio.ImageIO; import javax.imageio.ImageWriter; import javax.imageio.stream.ImageOutputStream; import org.apache.commons.io.FileUtils; import org.apache.commons.lang.StringUtils; import org.icepdf.core.exceptions.PDFException; import org.icepdf.core.exceptions.PDFSecurityException; import org.icepdf.core.pobjects.Document; import org.icepdf.core.pobjects.Page; import org.icepdf.core.util.GraphicsRenderingHints; import com.artofsolving.jodconverter.DocumentConverter; import com.artofsolving.jodconverter.openoffice.connection.OpenOfficeConnection; import com.artofsolving.jodconverter.openoffice.connection.SocketOpenOfficeConnection; import com.artofsolving.jodconverter.openoffice.converter.OpenOfficeDocumentConverter; import common.cdk.config.files.appconfig.WebAppConfig; //该类用来将doc、ppt文件转成pdf文件,并且将pdf的第一页内容生成图片,且根据一定的大小进行缩放 public class PDFUtils { private static int maxW = 600;//缩略图最大的宽度,此值只作参考 private static double point = 0.2;//计算出比例之后,添加富余的百分比 private static String postfix="_2";//缩略图的名称:原图的名称+_2+.+后缀名 private static final String FILETYPE_JPG = "png"; private static int pdfPage = 1; private static int degree = 270;//旋转角度 /** * 该方法用来将doc、ppt等office文件转换成pdf,并根据首页内容生成缩略图 * @param filePath:需要进行转换的文件路径,如:D:\bfp\2017\12\12\00000000001.png * **/ public static void tranferFileToPDF(String filePath){ try{ if(new File(filePath)==null){//为空 直接返回 return ; } //1、判断是否有同名的图片文件 File targetFile = new File(filePath); //System.out.println("原始文件路径:"+filePath); String targetFileName = targetFile.getName();//传递过来的文件名称 String thumFilePath = targetFile.getParentFile().getAbsolutePath()+File.separator+targetFileName.substring(0,targetFileName.lastIndexOf(".")+1)+FILETYPE_JPG;//缩略图文件路径 //System.out.println("缩略图路径(是否存在):"+thumFilePath); File thumFile = new File(thumFilePath); if(thumFile.exists() && thumFile.isFile()){//是个文件且存在,那么不需要再处理了,因为已经生成过了 //System.out.println("同名缩略图存在(路径:"+thumFilePath+")"); return ; } //2、判断是不是pdf文件,若是则生成缩略图,否则生成pdf String pdfFilePath="";//pdf文件路径 String extName = targetFileName.substring(targetFileName.lastIndexOf(".")+1); //System.out.println("文件后缀名:"+extName); int fileType = getFileType(extName); //System.out.println("文件类型:"+fileType+"(1-图片类型 2-word 3-ppt 4-pdf 0-除了以上的其他类型)"); if(fileType==0 || fileType==1) return ;//为0、1的不处理(0-不能处理 1-不需要处理) if(fileType==2 || fileType==3){//word或者ppt,需要转成pdf文件 //3、转成pdf String pdfName = targetFileName.substring(0,targetFileName.lastIndexOf(".")+1)+"pdf"; pdfFilePath = targetFile.getParentFile().getAbsolutePath()+File.separator+pdfName; //System.out.println("需要转成的PDF文件路径:"+pdfFilePath); officeToPdf(targetFile,new File(pdfFilePath)); } //4、根据pdf生成缩略图 //本身就是PDF文件或者转换成功,那么将首页内容生成缩略图 if(fileType==4) pdfFilePath = filePath; if(pdfFilePath.length()>0 && new File(pdfFilePath).exists() && new File(pdfFilePath).isFile()){ //4.1、生成图片 int[] result = tranfer(pdfFilePath,pdfPage); if(result!=null && result.length==2){//说明有返回结果 //4.2、若是图片太大,那么生成缩略图 String thumPath = ""; //System.out.println("生成的缩略图路径:"+thumPath); if(result[0]>maxW){//宽度超过maxW生成缩略图 //生成缩略图 //System.out.println("缩略图路径:"+thumPath); thumPath = (thumFilePath.substring(0,thumFilePath.lastIndexOf(".")))+postfix+(thumFilePath.substring(thumFilePath.lastIndexOf("."))); zoomImageScale(new File(thumFilePath),thumPath); } //3、宽比高大,那么默认生成的是横向的,需要旋转 /* if(result[0]>result[1]){ if(!new File(thumPath).exists()){//说明生成的图片本身比较小,没有生成缩略图,那么复制一张用来旋转 FileUtils.copyFile(new File(thumPath),new File(thumPath)); } BufferedImage img = rotate(ImageIO.read(new File(thumPath)),degree);//旋转一下(90度???待优化,未必是90度,也可能是270度,需要根据图片的朝向进行判断) ImageIO.write(img, FILETYPE_JPG, new File(thumPath)); } */ //4、删除原始图片(根据pdf内容生成的图片),将旋转后的或者缩略图重命名为原始图片的名字 if(thumPath.length()>0){//说明有生成过缩略图(代码生成的,而不是根据PDF内容生成的) if(new File(thumFilePath).exists() && new File(thumFilePath).isFile()){//存在且是个文件 new File(thumFilePath).delete();//删除原始文件 } new File(thumPath).renameTo(new File(thumFilePath));//重命名 } } } }catch(Exception e){ e.printStackTrace(); } } /** * 该方法用来判断文件类型,并返回属于哪一类 * @param extName:文件后缀 * @return 1-图片类型 2-word 3-ppt 4-pdf 0-除了以上的其他类型 * */ private static int getFileType(String extName){ if(extName!=null && extName.length()>0){ extName = extName.trim().toLowerCase();//全部转换成小写 if(extName.endsWith("jpg") || extName.endsWith("gif") || extName.endsWith("png") || extName.endsWith("jpeg") || extName.endsWith("bmp") || extName.endsWith("tif")){//tif扫描件 return 1; }else if(extName.endsWith("doc") || extName.endsWith("docx")){ return 2; }else if(extName.endsWith("ppt") || extName.endsWith("pptx")){ return 3; }else if(extName.endsWith("pdf")){ return 4; }else { return 0; } }else{ return 0; } } /** * 该方法用来转成PDF文件 * @param inputFile:转变成pdf文件的文件 * @param outputFile:PDF文件对象 * */ public static void officeToPdf(File inputFile,File outputFile) { // 链接 一个运行在8100端口的OpenOffice.org 实例 OpenOfficeConnection connection = new SocketOpenOfficeConnection(8100); try { connection.connect(); //进行连接 // 创建一个converter对象并转换格式 DocumentConverter converter = new OpenOfficeDocumentConverter(connection); converter.convert(inputFile, outputFile); } catch (ConnectException cex) { cex.printStackTrace(); } finally { if (connection != null) { connection.disconnect(); //关闭连接 connection = null; } } } /** * * 将指定的pdf文件转换为指定路径的图片 * @param filepath 原文件路径,例如d:/test/test.pdf * @param zoom 缩略图显示倍数,1表示不缩放,0.3则缩小到30% * @param pages:将第几页转换成pdf * @param int[img_width,img_height]:返回图片的长度和宽度 */ public static int[] tranfer(String filepath,int pages) throws PDFException, PDFSecurityException, IOException { Document document = null; float rotation = 0f; document = new Document(); document.setFile(filepath); int maxPages = document.getPageTree().getNumberOfPages(); //System.out.println("总共有多少页:"+maxPages); float zoom = 1;//默认缩放比例 // String originalPath = imagepath + new File(filepath).getName() + "_" + new DecimalFormat("000").format(pages) + "." + FILETYPE_JPG; String originalName = new File(filepath).getName(); // System.out.println("图片路径:"+new File(filepath).getParent()+"\t图片名称:"+originalName); String originalPath = new File(filepath).getParent() + File.separator+(originalName.substring(0,originalName.lastIndexOf("."))) + "." + FILETYPE_JPG; //System.out.println("生成的图片的名称:"+originalPath); int[] result = null; if(pages<=maxPages){ pages = (pages==0)?pages:pages-1;//传过来的是0页那么就使用0,否则减去1 BufferedImage img = (BufferedImage) document.getPageImage(pages, GraphicsRenderingHints.SCREEN, Page.BOUNDARY_CROPBOX, rotation,zoom); if(img==null){//说明文件生成失败了 Vector v = document.getPageImages(pages); //System.out.println("第"+(pages+1)+"页有几张图片:"+v.size()); img = (BufferedImage) v.get(0); }else{//说明成功啦 if(img.getWidth()>=maxW){ float zoom2 = getZoomByWidth(img.getWidth()); img = (BufferedImage) document.getPageImage(pages, GraphicsRenderingHints.SCREEN, Page.BOUNDARY_CROPBOX, rotation,zoom2); } } /* *有时候:当pdf文件是由多张图片转换而成时,使用document.getPageImage(pages, GraphicsRenderingHints.SCREEN, Page.BOUNDARY_CROPBOX, rotation,zoom)会得到空白页, *为避免这种情况判断document.getPageText(pages)是否有值,若没有值通常都是由图片转成的pdf文件,此时使用document.getPageImages(pages)来获取第一张图片, *而通常情况下使用这种方式获取到的图片大部分都是横向的,后期又需要通过方法去旋转 PageText pt= document.getPageText(pages); if(pt!=null && pt.toString().length()>0){//说明不是图片转成的pdf文件,那么可以获取 //先按照正常比例获取图片,再根据图片的大小计算相应的缩放比例 img = (BufferedImage) document.getPageImage(pages, GraphicsRenderingHints.SCREEN, Page.BOUNDARY_CROPBOX, rotation,zoom); if(img.getWidth()>=maxW){ float zoom2 = getZoomByWidth(img.getWidth()); img = (BufferedImage) document.getPageImage(pages, GraphicsRenderingHints.SCREEN, Page.BOUNDARY_CROPBOX, rotation,zoom2); } }else{ Vector v = document.getPageImages(pages); //System.out.println("第"+(pages+1)+"页有几张图片:"+v.size()); img = (BufferedImage) v.get(0); } */ if(img!=null){ result = new int[2]; result[0] = img.getWidth(); result[1] = img.getHeight(); //开始生成图片 Iterator iter = ImageIO.getImageWritersBySuffix(FILETYPE_JPG); ImageWriter writer = (ImageWriter) iter.next(); // System.out.println(); FileOutputStream out = new FileOutputStream(new File(originalPath)); ImageOutputStream outImage = ImageIO.createImageOutputStream(out); writer.setOutput(outImage); writer.write(new IIOImage(img, null, null)); outImage.close(); out.close(); img.flush(); document.dispose(); //System.out.println("直接生成,转换完成,图片路径:"+new File(originalPath).getAbsolutePath()); } }else{ System.out.println("转换失败"); } return result; } /** * 按指定高度 等比例缩放图片 * @param imageFile * @param thumPath:缩略图路径,包括路径+名称 * @throws IOException */ public static String zoomImageScale(File imageFile,String thumPath){ try{ if(!imageFile.canRead()) return null; BufferedImage bufferedImage = ImageIO.read(imageFile); if (null == bufferedImage) return null; int originalWidth = bufferedImage.getWidth(); int originalHeight = bufferedImage.getHeight(); //获取缩略图的路径 String originalPath = imageFile.getAbsolutePath(); //计算新的高度和宽度 double scale = getImgScale(originalWidth); if(scale==1){//为1,说明按照原图生成缩略图,也就是复制一张图 //System.out.println("复制图片,路径为:"+originalPath); FileUtils.copyFile(new File(originalPath),new File(thumPath)); }else{//按照要求生成一张 int newWidth = (int)(originalWidth*scale); int newHeight = (int)(originalHeight*scale); //System.out.println("原始路径:"+originalPath+"\n缩略图路径:"+thumPath); zoomImageUtils(imageFile,thumPath, bufferedImage,newWidth,newHeight); } return thumPath; }catch(Exception e){ e.printStackTrace(); return null; } } private static void zoomImageUtils(File imageFile, String newPath, BufferedImage bufferedImage, int width, int height){ String suffix = StringUtils.substringAfterLast(imageFile.getName(), "."); try{ // 处理 png 背景变黑的问题 if(suffix != null && (suffix.trim().toLowerCase().endsWith("png") || suffix.trim().toLowerCase().endsWith("gif"))){ BufferedImage to= new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); Graphics2D g2d = to.createGraphics(); to = g2d.getDeviceConfiguration().createCompatibleImage(width, height, Transparency.TRANSLUCENT); g2d.dispose(); g2d = to.createGraphics(); Image from = bufferedImage.getScaledInstance(width, height, Image.SCALE_AREA_AVERAGING); g2d.drawImage(from, 0, 0, null); g2d.dispose(); ImageIO.write(to, suffix, new File(newPath)); }else{ int tType = bufferedImage.getType(); if(0 == tType){ tType = 5; } BufferedImage newImage = new BufferedImage(width, height,tType); Graphics g = newImage.getGraphics(); g.drawImage(bufferedImage, 0, 0, width, height, null); g.dispose(); ImageIO.write(newImage, suffix, new File(newPath)); newImage.flush(); } }catch(Exception e){ e.printStackTrace(); } } /** * 该方法根据图片的宽度重新计算缩放比例(暂定????) * @param width:图片的宽度 * **/ public static float getZoomByWidth(int width){ if(width>600 && width<=700){ return 0.95f; }else if(width>700 && width<=850){ return 0.9f; }else if(width>850 && width<=1100){ return 0.85f; }else if(width>1100 && width<=1500){ return 0.75f; }else{//>1500的按照50%进行缩放 return 0.5f; } } /** * 该方法根据原始图片的宽度/高度获取适合的比例 * 原则:不得少于maxW,取与maxW最近的值 * @param originalWidth:原始宽度 * **/ public static double getImgScale(int originalWidth){ initMaxWidth();//初始化最大宽度和富余值 double scale = (double)maxW/originalWidth; scale = scale+ point; return Double.parseDouble(new DecimalFormat("0.00").format(scale));//保留2位小数 } //该方法用来初始化最大的宽度和富余百分比 public static void initMaxWidth(){ if(maxW<=0){//缩略图最大宽度 if(WebAppConfig.app("maxW")!=null && WebAppConfig.app("maxW").trim().length()>0){ try{ maxW = Integer.parseInt(WebAppConfig.app("maxW")); }catch(Exception e){ maxW = 400; e.printStackTrace(); } }else maxW = 400; } if(point<=0){//计算出比例之后,添加两个富余的百分比 if(WebAppConfig.app("point")!=null && WebAppConfig.app("point").trim().length()>0){ try{ point = Double.parseDouble(WebAppConfig.app("point")); }catch(Exception e){ point = 0.02; e.printStackTrace(); } }else point = 0.02; } } public static BufferedImage rotate(Image src, int angel) { int src_width = src.getWidth(null); int src_height = src.getHeight(null); // calculate the new image size Rectangle rect_des = CalcRotatedSize(new Rectangle(new Dimension(src_width, src_height)), angel); //System.out.println(rect_des); BufferedImage res = null; res = new BufferedImage(rect_des.width, rect_des.height, BufferedImage.TYPE_INT_RGB); Graphics2D g2 = res.createGraphics(); // transform g2.translate((rect_des.width - src_width) / 2,(rect_des.height - src_height) / 2); g2.rotate(Math.toRadians(angel), src_width / 2, src_height / 2); g2.drawImage(src, null, null); return res; } public static Rectangle CalcRotatedSize(Rectangle src, int angel) { // if angel is greater than 90 degree, we need to do some conversion if (angel >= 90) { if(angel / 90 % 2 == 1){ int temp = src.height; src.height = src.width; src.width = temp; } angel = angel % 90; } double r = Math.sqrt(src.height * src.height + src.width * src.width) / 2; double len = 2 * Math.sin(Math.toRadians(angel) / 2) * r; double angel_alpha = (Math.PI - Math.toRadians(angel)) / 2; double angel_dalta_width = Math.atan((double) src.height / src.width); double angel_dalta_height = Math.atan((double) src.width / src.height); int len_dalta_width = (int) (len * Math.cos(Math.PI - angel_alpha - angel_dalta_width)); int len_dalta_height = (int) (len * Math.cos(Math.PI - angel_alpha - angel_dalta_height)); int des_width = src.width + len_dalta_width * 2; int des_height = src.height + len_dalta_height * 2; return new java.awt.Rectangle(new Dimension(des_width, des_height)); } public static void main(String[] args){ //String testPath = "D:\\bfp\\2017\\12\\12\\00000000001.png"; //String testPath = "D:\\bfp\\2017\\12\\12\\00000000000.pdf"; //String testPath = "D:\\bfp\\2017\\12\\12\\00000000000.doc"; String testPath = "D:\\bfp\\2017\\9\\26\\00000000010.xls"; //String testPath = "00000000001.png"; //System.out.println(testPath); //String extName = testPath.substring(testPath.lastIndexOf(".")+1); //System.out.println("后缀名:"+extName); tranferFileToPDF(testPath); } }
解释一下:
tranfer()方法中有一大段注释的地方,其实那是先前的一种处理方式。在将一般的pdf文件转成图片时,使用document.getPageImage(pages, GraphicsRenderingHints.SCREEN, Page.BOUNDARY_CROPBOX, rotation,zoom)方法就OK,但是当碰到“由图片转换而成的pdf”时(何以判断??打开pdf,选中,右键,若是只有一个“复制图片”的功能,那么这个pdf文件就是由图片转成的),生成的pdf文件是空白的,无论这个pdf文件是大是小都是空白的。为避免这种情况判断document.getPageText(pages)是否有值,若没有值通常都是由图片转成的pdf文件,此时使用document.getPageImages(pages)来获取第一张图片,此时获取到的图片大部分都是横向的(图片是横的内容也是横着的), 后期又需要通过方法去旋转,所以在后面的业务逻辑处理中又加了图片旋转的功能(那个功能写的比较死,并没有根据图片的方向来旋转)。
后来在修改图片的后缀名问题是(先前使用的jpg,后改成png),发现图片PDF不会再出现空白页,而且试了很多个pdf文件都能正常生成,生成的图片也不再是横向的,这就解决了后面旋转的问题(图片正常显示不需要再旋转了),于是就把这种处理方法注释掉了,同样旋转的代码也注释了。
最后再来一个批量处理的代码:将某个目录下的doc/docx/ppt/pptx转成pdf,并生成图片
//该方法用来初始化历史数据:将doc/ppt文件转换成成pdf文件并根据首页内容生成缩略图 public String initFileToPdf() throws Exception{ String msg=""; try{ //最多定位到5级盘符 String field1 = request.getParameter("field1");//盘符 String field2 = request.getParameter("field2");//二级目录 String field3 = request.getParameter("field3");//三级目录 String field4 = request.getParameter("field4");//四级目录 String field5 = request.getParameter("field5");//四级目录 String path=""; if((field1==null || field1.toString().length()<=0) || (field2==null || field2.toString().length()<=0)){ writeLoggerForInfo(null,msg,"处理完成:至少精确到二级目录"); }else{ path = field1+":"+File.separator+field2; if(field3!=null && field3.trim().length()>0){ path=path+File.separator+field3; } if(field4!=null && field4.trim().length()>0){ path=path+File.separator+field4; } if(field5!=null && field5.trim().length()>0){ path=path+File.separator+field5; } msg="将doc/ppt文件转换成成pdf文件并根据首页内容生成缩略图(处理目录:"+path+")"; System.out.println("处理目录:"+path); //开始处理 writeLoggerForInfo(null,msg,"开始处理"); getDirectory(new File(path)); writeLoggerForInfo(null,msg,"处理完成"); } }catch(Exception e){ writeLoggerForException(msg,null,e); e.printStackTrace(); } return null; } private void getDirectory(File file) { PDFUtils pdfUtils = new PDFUtils(); if(file==null || !file.exists() || !file.isDirectory()) return ; File flist[] = file.listFiles(); if (flist == null || flist.length == 0)return ; for (File f : flist) { if (f.isDirectory()) { //这里将列出所有的文件夹 //System.out.println("正在处理的目录:" + f.getAbsolutePath()); logger.info("正在处理的目录:" + f.getAbsolutePath()); getDirectory(f); } else { //这里将列出所有的文件 //System.out.println("正在处理的文件:" + f.getAbsolutePath()); logger.info("正在处理的文件:" + f.getAbsolutePath()); pdfUtils.tranferFileToPDF(f.getAbsolutePath()); } } }
测试:
要转换的目录:D:/test/2017/12/15
请求链接:fileRouter!initFileToPdf.action?field1=D&field2=test&field3=2017&field4=12&field5=15