说明:
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