在作软件工程的课程设计的时候,咱们小组选择作一个资料分享网站,网站最重要的功能固然就是上传文件和下载文件。可是这中间就须要一个比较重要的过程:预览。
预览最终结果是一张长图,很长很长的png图片。大体能够分为下面这几个步骤:php
四个步骤,分别须要用到不一样的工具:前端
第一步:对于WORD转PDF,在度娘的帮助下,咱们决定使用Java语言实现这一功能。使用开源的openoffice+jodconverter来对WORD进行转换。首先咱们要考虑php如何调用Java,很幸运,有一个叫作JavaBridge的东西为咱们解决了这个问题,JavaBridge的使用在百度中有大量的博客教程(ps:虽然我对国内这些博客互相抄袭,还错误百出很看不习惯,但确实也有好的博客,而且数量不少);java
而后就是要安装OpenOffice,这个很简单,不管是Windows仍是Linux都不难(直接百度搜索openoffice安装便可);
最后下载jodconverter的jar包,编写程序将WORD转为PDF。linux
源码以下web
import java.io.File; import java.io.IOException; 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; public class PDFConverter { /** * 将WORD文档转换为PDF * @param srcPath WORD文档路径 * @param desPath 目标PDF保存路径 * @param pages 转换页数 * @throws IOException */ public void Word2Pdf(String srcPath, String desPath) throws IOException { // 源文件目录 File inputFile = new File(srcPath); if (!inputFile.exists()) { System.out.println("源文件不存在!"); System.out.println(srcPath + ", " + desPath); return; } // 输出文件目录 File outputFile = new File(desPath); if (!outputFile.getParentFile().exists()) { outputFile.getParentFile().mkdirs(); } // 调用openoffice服务线程 // String command = "C:\\Program Files (x86)\\OpenOffice 4\\program\\soffice.exe -headless -accept=\"socket,host=127.0.0.1,port=8100;urp;\""; String command = "/opt/openoffice4/program/soffice -headless -accept=\"socket,host=127.0.0.1,port=8100;urp;\" -nofirststartwizard"; Process p = Runtime.getRuntime().exec(command); // 链接openoffice服务 OpenOfficeConnection connection = new SocketOpenOfficeConnection( "127.0.0.1", 8100); connection.connect(); // 转换word到pdf DocumentConverter converter = new OpenOfficeDocumentConverter( connection); converter.convert(inputFile, outputFile); // 关闭链接 connection.disconnect(); // 关闭进程 p.destroy(); System.out.println("转换完成!"); } }
在程序中咱们建立一个线程来打开OpenOffice的服务
Process p = Runtime.getRuntime().exec(command);
这条代码的做用至关于在命令行(终端)输入command字符串,而command字符串就是咱们启动openoffice服务的命令。后面链接openoffice而后利用它提供的接口将WORD转为PDF便可。(注意:
注释起来的command是Windows下的启动命令,由于Windows系统和linux系统中openoffice安装路径不一样,因此须要使用不一样的路径启动服务,因此在安装OpenOffice时必定要注意安装路径)
第二步:将一个大的PDF拆分为小的PDF,多是PHP这方面的支持不够,也多是我对Java颇有好感,这一步我选择的是使用Apache的pdfbox结合Java实现的。在apache官网中找到pdfbox,下载fontbox-2.0.15.jar、pdfbox-2.0.15.jar、commons-logging-1.2.jar这三个jar包,可是我在apahce官网上面并无找到最后一个jar包,是在别人分享的百度云盘里面下载的,因此最后我会把我用到的全部jar包上传到百度云并提供永久下载连接;得到这三个jar包后编写程序;数据库
源码以下apache
/** * 将一个大pdf拆分为小pdf * @param src 大PDF路径 * @param dest 小PDF保存路径 * @param pages 拆分页数 */ public void split(String src, String dest, int pages) { File srcFile = new File(src); if(!srcFile.exists()) { System.out.println("原文件不存在"); return; } // 若是目标路径的父目录不存在,则建立 File destFile = new File(dest); if(!destFile.getParentFile().exists()) { destFile.getParentFile().mkdirs(); } try { System.out.println("开始拆分"); // 加载原PDF文件 PDDocument pdf = PDDocument.load(srcFile, MemoryUsageSetting.setupTempFileOnly()); // 获取原PDF文件总页数 int pageCount = pdf.getPages().getCount(); // 当所须要的页数大于总页数时,按最大总页数进行拆分 if(pages > pageCount) { pages = pageCount; } PDDocument newPdf = new PDDocument(); for(int i=0;i<pages;i++) { newPdf.addPage(pdf.getPage(i)); } newPdf.save(destFile); pdf.close(); newPdf.close(); System.out.println("拆分结束"); } catch (IOException e) { e.printStackTrace(); } }
第三步:将PDF转为PNG图片,很幸运在pdfbox中提供了这样的功能,因此这一步不须要任何工具包
直接就能够编写代码
/** * 将pdf转为png图片 * @param src 原pdf路径 * @param dest 图片的父目录 */ public void Pdf2Png(String src, String dest) { File srcFile = new File(src); if(!srcFile.exists()) { System.out.println("源文件不存在"); return; } File destFile = new File(dest); if(!destFile.exists()) { destFile.mkdirs(); } try { PDDocument doc = PDDocument.load(srcFile); PDFRenderer renderer = new PDFRenderer(doc); int pageCount = doc.getNumberOfPages(); for(int i=0;i<pageCount;i++){ BufferedImage image = renderer.renderImageWithDPI(i, 300); File file = new File(dest + "\" + i + ".png"); ImageIO.write(image, "PNG", file); } doc.close(); } catch (IOException e) { e.printStackTrace(); } }
因为第二步和第三步用到了一样的外部jar包,因此我把它们放在同一个项目,下面是完整的项目编程
import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; import javax.imageio.ImageIO; import org.apache.pdfbox.io.MemoryUsageSetting; import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.rendering.PDFRenderer; public class PDFProcess { /** * 将pdf转为png图片 * @param src 原pdf路径 * @param dest 图片的父目录 */ public void Pdf2Png(String src, String dest) { File srcFile = new File(src); if(!srcFile.exists()) { System.out.println("源文件不存在"); return; } File destFile = new File(dest); if(!destFile.exists()) { destFile.mkdirs(); } try { PDDocument doc = PDDocument.load(srcFile); PDFRenderer renderer = new PDFRenderer(doc); int pageCount = doc.getNumberOfPages(); for(int i=0;i<pageCount;i++){ BufferedImage image = renderer.renderImageWithDPI(i, 300); File file = new File(dest + "\" + i + ".png"); ImageIO.write(image, "PNG", file); } doc.close(); } catch (IOException e) { e.printStackTrace(); } } /** * 将一个大pdf拆分为小pdf * @param src 大PDF路径 * @param dest 小PDF保存路径 * @param pages 拆分页数 */ public void split(String src, String dest, int pages) { File srcFile = new File(src); if(!srcFile.exists()) { System.out.println("原文件不存在"); return; } // 若是目标路径的父目录不存在,则建立 File destFile = new File(dest); if(!destFile.getParentFile().exists()) { destFile.getParentFile().mkdirs(); } try { System.out.println("开始拆分"); // 加载原PDF文件 PDDocument pdf = PDDocument.load(srcFile, MemoryUsageSetting.setupTempFileOnly()); // 获取原PDF文件总页数 int pageCount = pdf.getPages().getCount(); // 当所须要的页数大于总页数时,按最大总页数进行拆分 if(pages > pageCount) { pages = pageCount; } PDDocument newPdf = new PDDocument(); for(int i=0;i<pages;i++) { newPdf.addPage(pdf.getPage(i)); } newPdf.save(destFile); pdf.close(); newPdf.close(); System.out.println("拆分结束"); } catch (IOException e) { e.printStackTrace(); } } }
最后一个合并PNG,这个要求直接使用php便可实现,不过须要GD2扩展库,若是是Windows下这个扩展是自带的,Linux下须要本身安装扩展
<?php /** * 竖直方向上合并图片(合并为png格式),目标图片的宽度取全部图片中宽度最大的那张,高度取全部图片高度之和 * @param array 一组图片的路径 * @param String $dest 合并以后的图片地址 */ public static function merge($source, String $dest) { $width = 0; // 合并后图片的宽 $height = 0; // 合并后图片的高 $arr = array(); for($i=0;$i<count($source);$i++) { $info = getimagesize($source[$i]); // 获取图片详细信息(宽、高、类型等) // 获取图片类型 $type = image_type_to_extension($info[2], false); $fun = "Imagecreatefrom{$type}"; // 根据图片类型构造一个符合该类型图片的读取函数 $arr[$i]['source'] = $fun($source[$i]); $arr[$i]['size'] = $info; if($arr[$i]['size'][0] > $width) { $width = $arr[$i]['size'][0]; } $height += $arr[$i]['size'][1]; } $merge = imagecreate($width, $height+10*count($source)); $space = imagecreate($width, 10); $dst_x = 0; $dst_y = 0; for($i=0;$i<count($source);$i++) { imagecopy($merge, $arr[$i]['source'], $dst_x, $dst_y, 0, 0, $arr[$i]['size'][0], $arr[$i]['size'][0]); imagecopy($merge, $space, $dst_x, $dst_y, 0, 0, $width, 10); $dst_y += $arr[$i]['size'][1]; } imagepng($merge, $dest); imagedestroy($merge); } ?>
具体的思想就是先建立一张空的长图,而后将要合并的图片一张一张放进去(用的是imagecopy()函数),这里我作了一个间隔处理,每两张图片之间间隔了10像素。到目前为止貌似全部的问题都获得了解决,咱们只须要将Java项目打包成jar包,放入JavaBridge所要求的jre环境的ext目录中,就能完成全部的功能了。windows
可是,当我将全部东西放入项目中运行时,会发生各类“意外”(特别是在Windows开发,而后源码移植到linux上时问题最为严重)。具体有哪些问题,下面我一一列举,而且将之与个人项目结合在一块儿说明服务器
File file = new File(dest + "\" + i + ".png");
若是你看懂了个人代码,就会知道问题所在。在Windows下一切运行正常,可是到Linux下PNG文件的文件名和生成路径就会发生变化,这里的""不会被看成路径分隔符了,而是看成文件名的一部分,其实修改起来也很简单:File file = new File(dest + File.separator + i + ".png");
第一种就是线程等待,让主线程等待,直到另外一个线程执行完毕后唤醒主线程;
第二种就是让openoffice服务长期开启,而不须要在程序中启动服务;
因为此时处于开发初期,小组选择先长期开启服务,等后期再改成线程等待策略。那么代码也得作相应的修改,将启动openoffice服务的代码删除便可,可是要记住须要手动启动服务。
方法一:将打包好的jar包用rar打开,将外部jar包直接复制到里面,至于复制到哪里,根据程序中import外部jar包张的类所使用的路径来判断,实在判断不出来就一个目录一个目录尝试。方法二:将外部jar包解压缩成许多class文件,将class文件复制到目标jar包中,这种方式我经过了测试。例如:将jodconverter的jar包解压缩后,有四个文件夹(com、drafts、org、META-INT),将这四个文件夹复制到目标jar包的顶层目录中。
方法三:若是能找到外部jar包的源代码,能够将源代码直接复制到项目中,跟项目一块儿打包成jar。这里的源代码指的是.java文件而不是.class文件,这种方式应该百分之百能成,可是通常想要找到源代码很难。
总结一下:
jar包的永久下载连接:
jodconverter:https://pan.baidu.com/s/1XwhiVhmlXxVvkPiiIkYi_Q
提取码:1dgj
pdfbox:https://pan.baidu.com/s/19bPBsoJhEv-m0l5ZLlMZbg
提取码:ymnt
JavaBridge:https://pan.baidu.com/s/1XKdC8vSLlmOGIGYRAmSQTA
提取码:k3lb
联系方式(qq):1518542802如果以为这篇博客有地方不明白能够加个人qq问我,在下必然知无不言言无不尽。