利用POI将word转换成html实现在线阅读

一、分析

通过网上找资料,发现用Java实现word在线阅读有以下的实现方式:

1

Word=>PDF(OpenOffice+JodConverter)=>SWF(pdf2swf)=>FlexPaper浏览

2

Word=>PDF(MSOffice+JACOB)=>SWF(pdf2swf)=>FlexPaper浏览

3

Word =>SWF (FlashPaper)=> FlexPaper浏览

4

Word=>SWF(print2flash)=> FlexPaper浏览

5

用第三方收费组件:PageOffice

6

1) 利用 POI把 Word2003转换成
html;

2) 利用OpenOffice+JodConverter将word2003转换成html

前4种方式,目标都是一致的,就是都将word文档转换成flash文件,只是中间的实现不大一样。前两种方式比较麻烦,都是先转成PDF,再转成SWF,最后用FlexPaper浏览。两种比较快捷,可直接将源文件转为SWF,用FlexPaper浏览。第二种方式用到的jacob是微软的组件,在Linux平台下基本是无望的了,第一个淘汰。由于FlashPaper不是开源工具,加之Win8系统不兼容(我现在用的系统),所以就没采用第三种实现方式。Print2flash是开源工具,即使公司产品中用到也不会出现版权纠纷,遗憾的是没找到如何用程序控制该工具转换文件的命令。所以第3,4种方式也淘汰了。通过下载,预使用,发现第5种方式用PageOffice是最省时省力的,也能将word文档完美的展现,但是,要钱!!好吧,一提到钱,此种实现只能暂作废。

后面一开始是想用OpenOffice+JodConverter实现转swf的,后面在逛百度文库的时候,发现一个让我很好奇的东西。就是,百度文库里的文档基本上都用html进行展示了,也就是说,我们上传的word文档,百度对其做了html转换的处理,与页面的嵌合也相当的好。这让我想到,我们的项目中是否也可以用此方式实现word的在线预览呢。

基于这个想法,我到谷歌找相关的资料,发现将word转html的开源工具没几个。其中,介绍得比较多的就是用POI进行转换,但是,由于POI对word的处理功能相当的弱,因此,开启了使用POI将wordàhtml的艰苦历程(后面发现网上有介绍用OpenOffice+JodConverter将word2003转换成html的方式,但是,我没有深究,有兴趣的同学可以去观望一下http://www.cnblogs.com/codeplus/archive/2011/10/22/2220952.html):

二、实现

1.      POI介绍:

Apache POI 是用Java编写的免费开源的跨平台的 Java API,Apache POI提供API给Java程式对Microsoft Office格式档案读和写的功能。POI为“Poor Obfuscation Implementation”的首字母缩写,意为“可怜的模糊实现”。

Apache POI 是创建和维护操作各种符合Office Open XML(OOXML)标准和微软的OLE 2复合文档格式(OLE2)的Java API。用它可以使用Java读取和创建,修改MS Excel文件.而且,还可以使用Java读取和创建MS Word和MSPowerPoint文件。Apache POI 提供Java操作Excel解决方案(适用于Excel97-2008)。

基本结构:

HSSF -提供读写Microsoft Excel XLS格式档案的功能。

XSSF -提供读写Microsoft Excel OOXML XLSX格式档案的功能。

HWPF -提供读写Microsoft Word DOC格式档案的功能。

HSLF -提供读写Microsoft PowerPoint格式档案的功能。

HDGF -提供读Microsoft Visio格式档案的功能。

HPBF -提供读Microsoft Publisher格式档案的功能。

HSMF -提供读Microsoft Outlook格式档案的功能。

其实,POI比较拿手的是处理Excel表格,即上面的HSSF及XSSF,我们的很多项目,只要涉及报表的,基本上都有用到它吧。用对于HWPF即处理DOC的包,功能就没有那么健全了,且API也不完善。

2.      poi相关包及依赖包配置。

3.      处理流程图:

1)   主体流程:

2)   进行word文档解释转换子流程

3)   处理表格子流程(略)

4)   处理图片子流程(略)

4.      代码实现

[java] view plain copy

  1. packagecom;
  2. importjava.awt.image.BufferedImage;
  3. importjava.io.BufferedWriter;
  4. importjava.io.File;
  5. importjava.io.FileInputStream;
  6. importjava.io.FileNotFoundException;
  7. importjava.io.FileOutputStream;
  8. importjava.io.IOException;
  9. importjava.io.OutputStream;
  10. importjava.io.OutputStreamWriter;
  11. importjavax.imageio.ImageIO;
  12. importorg.apache.poi.hwpf.HWPFDocument;
  13. importorg.apache.poi.hwpf.model.PicturesTable;
  14. importorg.apache.poi.hwpf.usermodel.CharacterRun;
  15. importorg.apache.poi.hwpf.usermodel.Paragraph;
  16. importorg.apache.poi.hwpf.usermodel.Picture;
  17. importorg.apache.poi.hwpf.usermodel.Range;
  18. importorg.apache.poi.hwpf.usermodel.Table;
  19. importorg.apache.poi.hwpf.usermodel.TableCell;
  20. importorg.apache.poi.hwpf.usermodel.TableIterator;
  21. importorg.apache.poi.hwpf.usermodel.TableRow;
  22. importorg.apache.xmlbeans.impl.piccolo.io.FileFormatException;
  23. /**
  24. * @Description: 利用poi将word简单的转换成html文件
  25. * @author 柯颖波
  26. * @date 2013-12-20 上午09:32:44
  27. * @version v1.0
  28. */
  29. publicclassWord2Html {
  30. /**
  31. * 回车符ASCII码
  32. */
  33. privatestaticfinalshortENTER_ASCII =13;
  34. /**
  35. * 空格符ASCII码
  36. */
  37. privatestaticfinalshortSPACE_ASCII =32;
  38. /**
  39. * 水平制表符ASCII码
  40. */
  41. privatestaticfinalshortTABULATION_ASCII =9;
  42. privatestaticString htmlText ="";
  43. privatestaticString htmlTextTbl ="";
  44. privatestaticintcounter =0;
  45. privatestaticintbeginPosi =0;
  46. privatestaticintendPosi =0;
  47. privatestaticintbeginArray[];
  48. privatestaticintendArray[];
  49. privatestaticString htmlTextArray[];
  50. privatestaticbooleantblExist =false;
  51. /**
  52. * 项目路径
  53. */
  54. privatestaticString projectRealPath ="";
  55. /**
  56. * 临时文件路径
  57. */
  58. privatestaticString tempPath ="/upfile/"+ File.separator +"transferFile"+ File.separator;
  59. /**
  60. * word文档名称
  61. */
  62. privatestaticString wordName ="";
  63. publicstaticvoidmain(String argv[]) {
  64. try{
  65. wordToHtml("F:\\SVN\\BobUtil\\web\\", "2012年高考广东数学(文)试卷解析(精析word版)(学生版).doc");
  66. catch(Exception e) {
  67. e.printStackTrace();
  68. }
  69. }
  70. /**
  71. * 读取每个文字样式
  72. *
  73. * @param fileName
  74. * @throws Exception
  75. */
  76. privatestaticvoidgetWordAndStyle(String fileName)throwsException {
  77. FileInputStream in = newFileInputStream(newFile(fileName));
  78. HWPFDocument doc = newHWPFDocument(in);
  79. Range rangetbl = doc.getRange();// 得到文档的读取范围
  80. TableIterator it = newTableIterator(rangetbl);
  81. intnum =100;
  82. beginArray = newint[num];
  83. endArray = newint[num];
  84. htmlTextArray = newString[num];
  85. tblExist = false;
  86. // 取得文档中字符的总数
  87. intlength = doc.characterLength();
  88. // 创建图片容器
  89. PicturesTable pTable = doc.getPicturesTable();
  90. // 创建段落容器
  91. htmlText = "<html><head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" /><title>"
  92. + doc.getSummaryInformation().getTitle()
  93. "</title></head><body><div style='margin:60px;text-align:center;'><div style='width:620px;text-align:left;line-height:24px;'>";
  94. // 创建临时字符串,好加以判断一串字符是否存在相同格式
  95. if(it.hasNext()) {
  96. readTable(it, rangetbl);
  97. }
  98. intcur =0;
  99. String tempString = "";
  100. for(inti =0; i < length -1; i++) {
  101. // 整篇<span class="wp_keywordlink"><a target=_blank href="http://www.it-crazy.com/" title="文章" target="_blank">文章</a></span>的字符通过一个个字符的来判断,range为得到文档的范围
  102. Range range = newRange(i, i +1, doc);
  103. CharacterRun cr = range.getCharacterRun(0);
  104. // beginArray=new int[num];
  105. // endArray=new int[num];
  106. // htmlTextArray=new String[num];
  107. if(tblExist) {
  108. if(i == beginArray[cur]) {
  109. htmlText += tempString + htmlTextArray[cur];
  110. tempString = "";
  111. i = endArray[cur] - 1;
  112. cur++;
  113. continue;
  114. }
  115. }
  116. if(pTable.hasPicture(cr)) {
  117. htmlText += tempString;
  118. // 读写图片
  119. try{
  120. readPicture(pTable, cr);
  121. catch(Exception e) {
  122. e.printStackTrace();
  123. }
  124. tempString = "";
  125. else{
  126. Range range2 = newRange(i +1, i +2, doc);
  127. // 第二个字符
  128. CharacterRun cr2 = range2.getCharacterRun(0);
  129. charc = cr.text().charAt(0);
  130. // System.out.println(c);
  131. // /System.out.println(i+"::"+range.getEndOffset()+"::"+range.getStartOffset()+"::"+c);
  132. // 判断是否为回车符
  133. if(c == ENTER_ASCII) {
  134. tempString += "<br/>";
  135. }
  136. // 判断是否为空格符
  137. elseif(c == SPACE_ASCII)
  138. tempString += " ";
  139. // 判断是否为水平制表符
  140. elseif(c == TABULATION_ASCII)
  141. tempString += "    ";
  142. // 比较前后2个字符是否具有相同的格式
  143. booleanflag = compareCharStyle(cr, cr2);
  144. if(flag)
  145. tempString += cr.text();
  146. else{
  147. String fontStyle = "<span style=\"font-family:"+ cr.getFontName() +";font-size:"
  148. + cr.getFontSize() / 2+"pt;";
  149. if(cr.isBold())
  150. fontStyle += "font-weight:bold;";
  151. if(cr.isItalic())
  152. fontStyle += "font-style:italic;";
  153. if(cr.isStrikeThrough())
  154. fontStyle += "text-decoration:line-through;";
  155. intfontcolor = cr.getIco24();
  156. int[] rgb =newint[3];
  157. if(fontcolor != -1) {
  158. rgb[0] = (fontcolor >>0) &0xff;// red;
  159. rgb[1] = (fontcolor >>8) &0xff;// green
  160. rgb[2] = (fontcolor >>16) &0xff;// blue
  161. }
  162. fontStyle += "color: rgb("+ rgb[0] +","+ rgb[1] +","+ rgb[2] +");";
  163. htmlText += fontStyle + "\">"+ tempString + cr.text() +"</span>";
  164. tempString = "";
  165. }
  166. }
  167. }
  168. htmlText += tempString + "</div></div></body></html>";
  169. // System.out.println(htmlText);
  170. }
  171. /**
  172. * 读写文档中的表格
  173. *
  174. * @param pTable
  175. * @param cr
  176. * @throws Exception
  177. */
  178. privatestaticvoidreadTable(TableIterator it, Range rangetbl)throwsException {
  179. htmlTextTbl = "";
  180. // 迭代文档中的表格
  181. counter = -1;
  182. while(it.hasNext()) {
  183. tblExist = true;
  184. htmlTextTbl = "";
  185. Table tb = (Table) it.next();
  186. beginPosi = tb.getStartOffset();
  187. endPosi = tb.getEndOffset();
  188. // System.out.println("............"+beginPosi+"...."+endPosi);
  189. counter = counter + 1;
  190. // 迭代行,默认从0开始
  191. beginArray[counter] = beginPosi;
  192. endArray[counter] = endPosi;
  193. htmlTextTbl += "<table border='1' cellpadding='0' cellspacing='0' >";
  194. for(inti =0; i < tb.numRows(); i++) {
  195. TableRow tr = tb.getRow(i);
  196. htmlTextTbl += "<tr align='center'>";
  197. // 迭代列,默认从0开始
  198. for(intj =0; j < tr.numCells(); j++) {
  199. TableCell td = tr.getCell(j);// 取得单元格
  200. intcellWidth = td.getWidth();
  201. // 取得单元格的内容
  202. for(intk =0; k < td.numParagraphs(); k++) {
  203. Paragraph para = td.getParagraph(k);
  204. CharacterRun crTemp = para.getCharacterRun(0);
  205. String fontStyle = "<span style=\"font-family:"+ crTemp.getFontName() +";font-size:"
  206. + crTemp.getFontSize() / 2+"pt;color:"+ crTemp.getColor() +";";
  207. if(crTemp.isBold())
  208. fontStyle += "font-weight:bold;";
  209. if(crTemp.isItalic())
  210. fontStyle += "font-style:italic;";
  211. String s = fontStyle + "\">"+ para.text().toString().trim() +"</span>";
  212. if(s =="") {
  213. s = " ";
  214. }
  215. // System.out.println(s);
  216. htmlTextTbl += "<td width="+ cellWidth +">"+ s +"</td>";
  217. // System.out.println(i + ":" + j + ":" + cellWidth + ":" + s);
  218. // end for
  219. // end for
  220. // end for
  221. htmlTextTbl += "</table>";
  222. htmlTextArray[counter] = htmlTextTbl;
  223. // end while
  224. }
  225. /**
  226. * 读写文档中的图片
  227. *
  228. * @param pTable
  229. * @param cr
  230. * @throws Exception
  231. */
  232. privatestaticvoidreadPicture(PicturesTable pTable, CharacterRun cr)throwsException {
  233. // 提取图片
  234. Picture pic = pTable.extractPicture(cr, false);
  235. BufferedImage image = null;// 图片对象
  236. // 获取图片样式
  237. intpicHeight = pic.getHeight() * pic.getAspectRatioY() /100;
  238. intpicWidth = pic.getAspectRatioX() * pic.getWidth() /100;
  239. if(picWidth >500) {
  240. picHeight = 500* picHeight / picWidth;
  241. picWidth = 500;
  242. }
  243. String style = " style='height:"+ picHeight +"px;width:"+ picWidth +"px'";
  244. // 返回POI建议的图片文件名
  245. String afileName = pic.suggestFullFileName();
  246. //单元测试路径
  247. String directory = "images/"+ wordName +"/";
  248. //项目路径
  249. //String directory = tempPath + "images/" + wordName + "/";
  250. makeDir(projectRealPath, directory);// 创建文件夹
  251. intpicSize = cr.getFontSize();
  252. intmyHeight =0;
  253. if(afileName.indexOf(".wmf") >0) {
  254. OutputStream out = newFileOutputStream(newFile(projectRealPath + directory + afileName));
  255. out.write(pic.getContent());
  256. out.close();
  257. afileName = Wmf2Png.convert(projectRealPath + directory + afileName);
  258. File file = newFile(projectRealPath + directory + afileName);
  259. try{
  260. image = ImageIO.read(file);
  261. catch(Exception e) {
  262. e.printStackTrace();
  263. }
  264. intpheight = image.getHeight();
  265. intpwidth = image.getWidth();
  266. if(pwidth >500) {
  267. htmlText += "<img style='width:"+ pwidth +"px;height:"+ myHeight +"px'"+" src=\""+ directory
  268. + afileName + "\"/>";
  269. else{
  270. myHeight = (int) (pheight / (pwidth / (picSize *1.0)) *1.5);
  271. htmlText += "<img style='vertical-align:middle;width:"+ picSize *1.5+"px;height:"+ myHeight
  272. "px'"+" src=\""+ directory + afileName +"\"/>";
  273. }
  274. else{
  275. OutputStream out = newFileOutputStream(newFile(projectRealPath + directory + afileName));
  276. // pic.writeImageContent(out);
  277. out.write(pic.getContent());
  278. out.close();
  279. // 处理jpg或其他(即除png外)
  280. if(afileName.indexOf(".png") == -1) {
  281. try{
  282. File file = newFile(projectRealPath + directory + afileName);
  283. image = ImageIO.read(file);
  284. picHeight = image.getHeight();
  285. picWidth = image.getWidth();
  286. if(picWidth >500) {
  287. picHeight = 500* picHeight / picWidth;
  288. picWidth = 500;
  289. }
  290. style = " style='height:"+ picHeight +"px;width:"+ picWidth +"px'";
  291. catch(Exception e) {
  292. // e.printStackTrace();
  293. }
  294. }
  295. htmlText += "<img "+ style +" src=\""+ directory + afileName +"\"/>";
  296. }
  297. if(pic.getWidth() >450) {
  298. htmlText += "<br/>";
  299. }
  300. }
  301. privatestaticbooleancompareCharStyle(CharacterRun cr1, CharacterRun cr2) {
  302. booleanflag =false;
  303. if(cr1.isBold() == cr2.isBold() && cr1.isItalic() == cr2.isItalic()
  304. && cr1.getFontName().equals(cr2.getFontName()) && cr1.getFontSize() == cr2.getFontSize()) {
  305. flag = true;
  306. }
  307. returnflag;
  308. }
  309. /**
  310. * 写文件(成功返回true,失败则返回false)
  311. *
  312. * @param s
  313. *            要写入的内容
  314. * @param filePath
  315. *            文件
  316. */
  317. privatestaticbooleanwriteFile(String s, String filePath) {
  318. FileOutputStream fos = null;
  319. BufferedWriter bw = null;
  320. s = s.replaceAll("EMBED","").replaceAll("Equation.DSMT4","");
  321. try{
  322. makeDir(projectRealPath, tempPath);// 创建文件夹
  323. File file = newFile(filePath);
  324. if(file.exists()) {
  325. returnfalse;
  326. }
  327. fos = newFileOutputStream(file);
  328. bw = newBufferedWriter(newOutputStreamWriter(fos,"utf-8"));
  329. bw.write(s);
  330. // System.out.println(filePath + "文件写入成功!");
  331. catch(FileNotFoundException fnfe) {
  332. fnfe.printStackTrace();
  333. catch(IOException ioe) {
  334. ioe.printStackTrace();
  335. finally{
  336. try{
  337. if(bw !=null)
  338. bw.close();
  339. if(fos !=null)
  340. fos.close();
  341. catch(IOException ie) {
  342. ie.printStackTrace();
  343. }
  344. }
  345. returntrue;
  346. }
  347. /**
  348. * 根据路径名生成多级路径
  349. *
  350. * @param url
  351. *            参数要以"\classes\cn\qtone\"或者"/classes/cn/qtone/"
  352. */
  353. privatestaticString makeDir(String root, String url) {
  354. String[] sub;
  355. url = url.replaceAll("\\/","\\\\");
  356. if(url.indexOf("\\") > -1) {
  357. sub = url.split("\\\\");
  358. else{
  359. return"-1";
  360. }
  361. File dir = null;
  362. try{
  363. dir = newFile(root);
  364. for(inti =0; i < sub.length; i++) {
  365. if(!dir.exists() && !sub[i].equals("")) {
  366. dir.mkdir();
  367. }
  368. File dir2 = newFile(dir + File.separator + sub[i]);
  369. if(!dir2.exists()) {
  370. dir2.mkdir();
  371. }
  372. dir = dir2;
  373. }
  374. catch(Exception e) {
  375. e.printStackTrace();
  376. return"-1";
  377. }
  378. returndir.toString();
  379. }
  380. /**
  381. * 将word文档转化,返回转化后的文件路径
  382. *
  383. * @param projectPath
  384. *            项目路径
  385. * @param relativeFilePath
  386. *            文件相对路径
  387. * @return 返回生成的htm路径(如果出错,则返回null)
  388. */
  389. publicstaticString wordToHtml(String projectPath, String relativeFilePath) {
  390. String resultPath = null;
  391. projectRealPath = projectPath;// 项目路径
  392. String filePath = "";
  393. // System.out.println(projectRealPath + tempPath);
  394. // System.out.println(makeDir(projectRealPath, tempPath));
  395. try{
  396. File file = newFile(projectPath + relativeFilePath);
  397. if(file.exists()) {
  398. if(file.getName().indexOf(".doc") == -1|| file.getName().indexOf(".docx") >0) {
  399. thrownewFileFormatException("请确认文件格式为doc!");
  400. else{
  401. wordName = file.getName();
  402. wordName = wordName.substring(0, wordName.indexOf("."));
  403. filePath = projectRealPath + tempPath + wordName + ".htm";
  404. synchronized(relativeFilePath) {// 处理线程同步问题
  405. File ff = newFile(filePath);
  406. if(!ff.exists()) {// 如果不存在则进行转换
  407. getWordAndStyle(projectPath + relativeFilePath);
  408. writeFile(htmlText, filePath);
  409. }
  410. }
  411. resultPath = tempPath + wordName + ".htm";
  412. }
  413. else{
  414. thrownewFileNotFoundException("没找到相关文件!");
  415. }
  416. catch(NullPointerException e) {
  417. e.printStackTrace();
  418. catch(FileNotFoundException e) {
  419. e.printStackTrace();
  420. catch(Exception e) {
  421. e.printStackTrace();
  422. }
  423. returnresultPath;
  424. }
  425. }
[java] view plain copy

  1. packagecom;
  2. importjava.io.ByteArrayInputStream;
  3. importjava.io.ByteArrayOutputStream;
  4. importjava.io.File;
  5. importjava.io.FileInputStream;
  6. importjava.io.FileOutputStream;
  7. importjava.io.InputStream;
  8. importjava.io.OutputStream;
  9. importjava.util.Scanner;
  10. importjava.util.zip.GZIPOutputStream;
  11. importjavax.xml.parsers.DocumentBuilder;
  12. importjavax.xml.parsers.DocumentBuilderFactory;
  13. importjavax.xml.transform.OutputKeys;
  14. importjavax.xml.transform.Transformer;
  15. importjavax.xml.transform.TransformerFactory;
  16. importjavax.xml.transform.dom.DOMSource;
  17. importjavax.xml.transform.stream.StreamResult;
  18. importnet.arnx.wmf2svg.gdi.svg.SvgGdi;
  19. importnet.arnx.wmf2svg.gdi.wmf.WmfParser;
  20. importorg.apache.batik.transcoder.TranscoderInput;
  21. importorg.apache.batik.transcoder.TranscoderOutput;
  22. importorg.apache.batik.transcoder.TranscodingHints;
  23. importorg.apache.batik.transcoder.image.PNGTranscoder;
  24. importorg.apache.batik.transcoder.wmf.tosvg.WMFTranscoder;
  25. importorg.apache.commons.lang.StringUtils;
  26. importorg.w3c.dom.Document;
  27. importorg.w3c.dom.Element;
  28. publicclassWmf2Png {
  29. publicstaticvoidmain(String[] args)throwsException {
  30. // convert("F:\\SVN\\BobUtil\\web\\25177.wmf");
  31. // System.out.println((20 / (21 * 1.0)));
  32. // svgToPng("F:\\SVN\\BobUtil\\web\\25177.svg", "F:\\SVN\\BobUtil\\web\\25177.png");
  33. }
  34. /**
  35. * @Description: 进行转换
  36. * @param filePath
  37. *            文件路径
  38. * @return 设定文件
  39. */
  40. publicstaticString convert(String filePath) {
  41. String pngFile = "";
  42. File wmfFile = newFile(filePath);
  43. try{
  44. if(!wmfFile.getName().contains(".wmf")) {
  45. thrownewException("请确认输入的文件类型是wmf");
  46. }
  47. // wmf -> svg
  48. String svgFile = filePath.replace("wmf","svg");
  49. wmfToSvg(filePath, svgFile);
  50. // 对svg做预出理
  51. PreprocessSvgFile(svgFile);
  52. // svg -> png
  53. pngFile = filePath.replace("wmf","png");
  54. svgToPng(svgFile, pngFile);
  55. // 删除 svg
  56. File file = newFile(svgFile);
  57. if(file.exists()) {
  58. file.delete();
  59. }
  60. // 删除 wmf
  61. if(wmfFile.exists()) {
  62. wmfFile.delete();
  63. }
  64. catch(Exception e) {
  65. try{
  66. e.printStackTrace();
  67. wmfToJpg(filePath);
  68. catch(Exception e1) {
  69. e1.printStackTrace();
  70. }
  71. }
  72. returnwmfFile.getName().replace("wmf","png");
  73. }
  74. /**
  75. * 将wmf转换为svg
  76. *
  77. * @param src
  78. * @param dest
  79. */
  80. publicstaticvoidwmfToSvg(String src, String dest)throwsException {
  81. booleancompatible =false;
  82. try{
  83. InputStream in = newFileInputStream(src);
  84. WmfParser parser = newWmfParser();
  85. finalSvgGdi gdi =newSvgGdi(compatible);
  86. parser.parse(in, gdi);
  87. Document doc = gdi.getDocument();
  88. OutputStream out = newFileOutputStream(dest);
  89. if(dest.endsWith(".svgz")) {
  90. out = newGZIPOutputStream(out);
  91. }
  92. output(doc, out);
  93. catch(Exception e) {
  94. throwe;
  95. }
  96. }
  97. /**
  98. * @Description: 输出svg文件
  99. * @param doc
  100. * @param out
  101. * @throws Exception
  102. *             设定文件
  103. */
  104. privatestaticvoidoutput(Document doc, OutputStream out)throwsException {
  105. TransformerFactory factory = TransformerFactory.newInstance();
  106. Transformer transformer = factory.newTransformer();
  107. transformer.setOutputProperty(OutputKeys.METHOD, "xml");
  108. transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
  109. transformer.setOutputProperty(OutputKeys.INDENT, "yes");
  110. transformer.setOutputProperty(OutputKeys.DOCTYPE_PUBLIC, "-//W3C//DTD SVG 1.0//EN");
  111. transformer.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM,
  112. "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd");
  113. transformer.transform(newDOMSource(doc),newStreamResult(out));
  114. out.flush();
  115. out.close();
  116. out = null;
  117. }
  118. /**
  119. * @Description:对svg文件做预处理(这里主要是调整大小,先缩小10倍,如果还大于默认值,则按比例缩小)
  120. * @param svgFile
  121. * @throws Exception
  122. *             设定文件
  123. */
  124. privatestaticvoidPreprocessSvgFile(String svgFile)throwsException {
  125. intdefaultWeight =500;// 默认宽度
  126. FileInputStream inputs = newFileInputStream(svgFile);
  127. Scanner sc = newScanner(inputs,"UTF-8");
  128. ByteArrayOutputStream os = newByteArrayOutputStream();
  129. while(sc.hasNextLine()) {
  130. String ln = sc.nextLine();
  131. if(!ln.startsWith("<!DOCTYPE")) {
  132. os.write((ln + "\r\n").getBytes());
  133. }
  134. }
  135. os.flush();
  136. DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
  137. DocumentBuilder builder;
  138. builder = factory.newDocumentBuilder();
  139. Document doc = null;
  140. try{
  141. doc = builder.parse(newByteArrayInputStream(os.toByteArray()));
  142. catch(Exception e) {
  143. inputs = newFileInputStream(svgFile);
  144. os = newByteArrayOutputStream();
  145. intnoOfByteRead =0;
  146. while((noOfByteRead = inputs.read()) != -1) {
  147. os.write(noOfByteRead);
  148. }
  149. os.flush();
  150. doc = builder.parse(newByteArrayInputStream(os.toByteArray()));
  151. finally{
  152. os.close();
  153. inputs.close();
  154. }
  155. intheight = Integer.parseInt(((Element) doc.getElementsByTagName("svg").item(0)).getAttribute("height"));
  156. intwidth = Integer.parseInt(((Element) doc.getElementsByTagName("svg").item(0)).getAttribute("width"));
  157. intnewHeight =0;// 新高
  158. intnewWidth =0;// 新宽
  159. newHeight = height / 10;// 高缩小10倍
  160. newWidth = width / 10;// 宽缩小10倍
  161. // 如果缩小10倍后宽度还比defaultHeight大,则进行调整
  162. if(newWidth > defaultWeight) {
  163. newWidth = defaultWeight;
  164. newHeight = defaultWeight * height / width;
  165. }
  166. ((Element) doc.getElementsByTagName("svg").item(0)).setAttribute("width", String.valueOf(newWidth));
  167. ((Element) doc.getElementsByTagName("svg").item(0)).setAttribute("height", String.valueOf(newHeight));
  168. OutputStream out = newFileOutputStream(svgFile);
  169. output(doc, out);
  170. }
  171. /**
  172. * 将svg图片转成png图片
  173. *
  174. * @param filePath
  175. * @throws Exception
  176. */
  177. publicstaticvoidsvgToPng(String svgPath, String pngFile)throwsException {
  178. File svg = newFile(svgPath);
  179. FileInputStream wmfStream = newFileInputStream(svg);
  180. ByteArrayOutputStream imageOut = newByteArrayOutputStream();
  181. intnoOfByteRead =0;
  182. while((noOfByteRead = wmfStream.read()) != -1) {
  183. imageOut.write(noOfByteRead);
  184. }
  185. imageOut.flush();
  186. imageOut.close();
  187. wmfStream.close();
  188. ByteArrayOutputStream jpg = newByteArrayOutputStream();
  189. FileOutputStream jpgOut = newFileOutputStream(pngFile);
  190. byte[] bytes = imageOut.toByteArray();
  191. PNGTranscoder t = newPNGTranscoder();
  192. TranscoderInput in = newTranscoderInput(newByteArrayInputStream(bytes));
  193. TranscoderOutput out = newTranscoderOutput(jpg);
  194. t.transcode(in, out);
  195. jpgOut.write(jpg.toByteArray());
  196. jpgOut.flush();
  197. jpgOut.close();
  198. imageOut = null;
  199. jpgOut = null;
  200. }
  201. /**
  202. * 将wmf图片转成png图片(备用方法,即当上面的转换失败时用这个)
  203. *
  204. * @param filePath
  205. * @throws Exception
  206. */
  207. publicstaticString wmfToJpg(String wmfPath)throwsException {
  208. //先wmf-->svg
  209. File wmf = newFile(wmfPath);
  210. FileInputStream wmfStream = newFileInputStream(wmf);
  211. ByteArrayOutputStream imageOut = newByteArrayOutputStream();
  212. intnoOfByteRead =0;
  213. while((noOfByteRead = wmfStream.read()) != -1) {
  214. imageOut.write(noOfByteRead);
  215. }
  216. imageOut.flush();
  217. imageOut.close();
  218. wmfStream.close();
  219. // WMFHeaderProperties prop = new WMFHeaderProperties(wmf);
  220. WMFTranscoder transcoder = newWMFTranscoder();
  221. TranscodingHints hints = newTranscodingHints();
  222. transcoder.setTranscodingHints(hints);
  223. TranscoderInput input = newTranscoderInput(newByteArrayInputStream(imageOut.toByteArray()));
  224. ByteArrayOutputStream svg = newByteArrayOutputStream();
  225. TranscoderOutput output = newTranscoderOutput(svg);
  226. transcoder.transcode(input, output);
  227. //再svg-->png
  228. ByteArrayOutputStream jpg = newByteArrayOutputStream();
  229. String jpgFile = StringUtils.replace(wmfPath, "wmf","png");
  230. FileOutputStream jpgOut = newFileOutputStream(jpgFile);
  231. byte[] bytes = svg.toByteArray();
  232. PNGTranscoder t = newPNGTranscoder();
  233. TranscoderInput in = newTranscoderInput(newByteArrayInputStream(bytes));
  234. TranscoderOutput out = newTranscoderOutput(jpg);
  235. t.transcode(in, out);
  236. jpgOut.write(jpg.toByteArray());
  237. jpgOut.flush();
  238. jpgOut.close();
  239. returnjpgFile;
  240. }
  241. }

重点难点解释探讨:

1)  读取表格部分:

a)        找出表格的开始与结束标记;

b)        遍历整个表格内容,逐个单元格的内容取出并追加到变量中。

2)  读取图片部分

a)        图片文件的格式问题。

如果图片格式为png或者jpg,则可以直接进行处理并加入标签中,前台的html展示没有问题,但是,如果图片格式为wmf(详细看附录1),则html无法对基解释,那么我们只能对其进行转换格式:

百度后,网上很多说法都建议用batik工具包进行格式转换,其实思路就是:wmfàsvgàpng。查阅相关资料(如附录2),发现其处理svg文件的能力相当的强,即从svg—>png这一步是比较完美的。但是,在处理wmf—>svg这一步却导致部分图像丢失,即失真的情况,且很严重。查看相关的api看是否参数设置问题,但是无论怎么设置,结果还是不尽人意。一度想放弃,找别的包。

后来,无意中,在csdn中有网友建议先用wmf2svg工具类将wmf转换为svg,再用batiksvg转换为png。Very
good!!有了这个思路,感觉已经看到署光了。

类写出来后,进行类型转换测试,确实效果很好,完全没有失真。于是将其嵌入word—>html这个工具类中。再用各种包含了wmf图片的文档进行测试。生成的html文件,基本没有问题,当时那个开心啊!!(我去,程序员也就这德行)

好景不长,放到正式项目进行测试过程中,发现有个别文档一进行转换,服务器就跨了,直接报内存溢出。通过排查检测,原来就是进行图片转换过程中,将内存给挤爆了。奇怪了,虽然知道图片处理是比较耗内存,但也没想到1G的内存,一下子就被挤爆(刚跑起来占去300M左右,一跑word转换功能,不过一会就报OutOfMemorry)。

一度怀疑,是不是batik这个工具包是不是有bug,处理不了大的svg。还将问题放上了bakit的官网。后来,查看相关资料后,发现是wmf2svg工具生成的svg的高与宽都太大了,举个例子:15040* 13088,宽高都达到上万级别,结果得到的象素是上亿的,不爆内存才怪。

用dom工具,将每一个生成的svg文件再进行预处理,即将其高与宽都先缩小一倍,如果宽度依然比500要大,则将其设成500,并将高也按比例缩小。经过此步骤生成的svg再用batik进行转换就没有任何问题了。

到这里,差不多已经解决图片转换的问题了,但是,在使用过程中,发现wmf2svg这个工具也不是很稳定,偶尔会报异常,并且,我测试发现,报异常的这个wmf用之前batik直接进行wmf—>svgàpng的方案可以成功生成没有失真的png,于是,在wmf2svg的产生异常进行捕捉,并调用了wmfToJpg(String wmfPath)的备用方法。到此,大部分的wmf转换问题已经解决。

b)        生成html文本的<img />标签的width与height问题。

如果图片格式原本为png的话,直接用

[java] view plain copy

  1. // 获取图片样式
  2. intpicHeight = pic.getHeight() * pic.getAspectRatioY() / 100;
[java] view plain copy

  1. intpicWidth = pic.getAspectRatioX() * pic.getWidth() /100;

即可以将图片的宽与高设置与word文档一致;但是,发果wmf格式,要分两种情况分析:

Ø  如果转换生成的png宽度不小于500,则将期作为一般图片处理:

[java] view plain copy

  1. BufferedImage  image = ImageIO.read(file);
  2. intpheight = image.getHeight();
  3. intpwidth = image.getWidth();

Ø  如果转换生成的png宽度小于500,则认为是一般的公式,则应该与它旁边的字体宽度相近,这里设成字体的1.5倍宽度,高度为:

[java] view plain copy

  1. myHeight= (int) (pheight / (pwidth / (picSize *1.0)) *1.5);

如果图片即非wmf与非png(如jpg)的情况下,上面获取高与宽的方法不起作用,不知道是不是POI的bug。只能按以下方式处理:

[java] view plain copy

  1. BufferedImage  image = ImageIO.read(file);
  2. intpheight = image.getHeight();
  3. intpwidth = image.getWidth();

即跟上面处理wmf的第一种方式一致。

三、结束语

讲到这,将word转换成html的处理也大体上讲完了。这几天的边学边用,特别是真正能解决问题的时候,非常有成就感。其实,上面的处理还存在以下的问题待解决的:

1)读取表格部分:

a)        表格中如果再含有表格,POI无法进行很好的区分,比如,有一个两行两列的表格中,第一行第一列中又包含了一个两行两列的表格,那POI会将此表格解释成:第一行为2+2*2 = 6个单元格;第二行为2个单元格,这样解释出来的表格就很怪异了。

b)        表格中有果有合并单格的情况,程序暂未做此处理(后续看不能优化),表格也很怪异。

c)        表格中如果有图像,程序没有做相应的处理。

2)读取图片部分:

a) 有部分wmf->png的方式有个别图片还是没有转换成功,会报异常,但没有影响整体的功能;

b) word有部分公式生成的图片无法识别模式,不知道是不是POI无法将其解释,还是其他原因,就是有文档,生成没有后缀的图片文件,且这部分文件无法读取,用图片工具也打不开,暂时未找到很好的解决方案。

3)读取word的目录:

在读取目录会出现将格式化符号也解释出来。

4)其他未知的一些问题,反正,就觉得用POI来解释word是件很坚苦的事情,如果全是文本还好,如果里面包含图片,表格,公式等这些对象的时候,POI就显得太弱了。

附:

1.       wmf文件:

MicrosoftOffice 的剪贴画使用的就是这个格式。

Wmf是WindowsMetafile 的缩写,简称图元文件,它是微软公司定义的一种Windows平台下的图形文件格式。

wmf格式文件的特点如下:

1)                 wmf格式文件是MicrosoftWindows操作平台所支持的一种图形格式文件,目前,其它操作系统尚不支持这种格式,如Unix、Linux等。

2)                 与bmp格式不同,wmf格式文件是和设备无关的,即它的输出特性不依赖于具体的输出设备。

3)                 其图象完全由Win32 API所拥有的GDI函数来完成。

4)                 wmf格式文件所占的磁盘空间比其它任何格式的图形文件都要小得多。

5)                 在建立图元文件时,不能实现即画即得,而是将GDI调用记录在图元文件中,之后,在GDI环境中重新执行,才可显示图象。

6)                 显示图元文件的速度要比显示其它格式的图象文件慢,但是它形成图元文件的速度要远大于其它格式。

2.      Batik介绍

Batik是使用svg格式图片来实现各种功能的应用程序以及Applet提供的一个基于java的工具包。

通过Batik,你可以在JAVA可以使用的地方操作SVG文档,您还可以在你的应用程序使用Batik模块来生成, 处理和转码SVG图像。Batik很容易让基于Java的应用程序或小程序来处理SVG内容。 例如,使用Batik的SVG的发生器模块 ,Java应用程序或小程序可以很轻松地导出SVG格式的图形到。用Batik的SVG的查看组件,应用程序或小程序可以很容易地集成SVG的浏览和交互功能。另一种可能性是使用Batik的模块转换成各种格式SVG的通过,如光栅图像(JPEG,PNG或TIFF格式)或其它矢量格式(EPS或PDF格式,后两者由于转码器由Apache
FOP提供)。 Batik工程创建的目的是为开发者提供一系列可以结合或单独使用来支持特殊的svg解决方案的核心模块。模块主要有SVGParser,SVGGernerator,SVGDOM。Batik工程的其他目的是使它具有高度的扩展性。

(SVG的规范:可缩放矢量图形(SVG),是一个W3C的推荐标准。 它定义了丰富的2D图形的XML语法,其中包括诸如透明度功能,几何形状,滤镜效果(阴影,灯光效果等),脚本和动画)

利用POI将word转换成html实现在线阅读相关推荐

  1. Word转换成PDF文件在线转换

    Word文档转换成PDF文件怎么转换?为了文档的安全性考虑,有时候需要将Word转换成PDF格式的.如何进行两者的的转换是成功的主要因素所在,小编也有过这样的经历个人使用后,感觉迅捷word转换成pd ...

  2. word转换成pdf转换器在线

    怎样把word转换成PDF?word是办公人员都会接触到的文件,可是有时候我们需要将word转换成PDF,因为PDF更具有专业性,显得更加正式.怎么实现两者的转换.为大家推荐迅捷PDF转换器. 这款w ...

  3. WORD转换成PDF转换器2015官方版?

    WORD转换成PDF转换器2015官方版 Word是我们工作中或多或少都要接触的文件格式,自己做一份文件的话一般都是以Word来做,因为是最常用的一种文档.可是当我们做出的文件要发给同事或者领导的话, ...

  4. 怎么样在线Word转换成PDF转换器

    导语:从事文字编辑行业的用户对于PDF资料文件转换成Word并不陌生,但有时候因为客观原因我们需要将编辑好的Word转换成PDF转换器在线http://app.xunjiepdf.com,方便客户浏览 ...

  5. Apache POI将HTML转换成Word

    Apache POI将HTML转换成Word 结果图如下: package com.poi.word;import java.io.FileOutputStream; import java.io.I ...

  6. java将office文档,word,ppt,pdf文档转换成swf文件在线预览

    java将office文档pdf文档转换成swf文件在线预览 第一步,安装openoffice.org openoffice.org是一套sun的开源office办公套件,能在widows,linux ...

  7. 利用poi读取word模板文件生成新的word文档

    利用poi读取word模板文件生成新的word文档 利用poi读取word模板文件,并回填逻辑数据,生成并导出需要的word文档源码.解决模板读取异常问题,提供wordUtils工具类(各种功能实现) ...

  8. java word模板poi生成文件_利用poi读取word模板文件生成新的word文档

    利用poi读取word模板文件生成新的word文档 利用poi读取word模板文件,并回填逻辑数据,生成并导出需要的word文档源码.解决模板读取异常问题,提供wordUtils工具类(各种功能实现) ...

  9. poi处理word内容的公式_利用poi操作word文档

    关键字:POI JAVA 批注 总页数 总字符数 一:认识POI Apache POI是一个开源的利用Java读写Excel.WORD等微软OLE2组件文档的项目.最新的3.5版本有很多改进,加入了对 ...

  10. 利用poi操作word文档(针对docx格式)

    一:认识POI  Apache POI是一个开源的利用Java读写Excel.WORD等微软OLE2组件文档的项目.最新的3.5版本有很多改进,加入了对采用OOXML格式的Office 2007支持, ...

最新文章

  1. 深度学习框架盘点和实践!
  2. iOS-应用之间调用
  3. Oracle 一些常用的数据字典
  4. JspWriter与PrintWriter的关系
  5. FCN网络训练 SIFTFLOW数据集
  6. OpenCV矩形检测
  7. 信安教程第二版-第20章数据库系统安全
  8. 125. 如何修改PHP的memory_limit限制
  9. 2022年10 款最佳计算机视觉开源数据标注工具
  10. LoadRunner 压力测试
  11. 根据录入的计算公式计算_增值税含税怎么计算?
  12. 计算机的键盘应用,电脑键盘应用小知识
  13. Python 二进制数与十进制数转换表的制作
  14. 假设用于通信的电文由字符集{a,b,c,d,e,f,g}中的字母构成。它们在电文中出现的频度分别为
  15. HTML5基础之代码入门
  16. IDEA牛逼!900行又臭又长的类重构,几分钟搞定
  17. MySQL实战开发技巧
  18. 百度京东加持的新潮传媒 已成为分众传媒最大的敌人
  19. 解析石墨烯技术专利:锂离子电池成热点技术领域
  20. 对测试驱动开发的一些理解

热门文章

  1. 《张志俊揭秘太极拳》读书摘编
  2. Unity3D音效问题
  3. AMAZON SP API Feed
  4. 【opencvsharp】opencvsharp_samples.core示例代码笔记
  5. 从零开始学习Openwrt教程
  6. 为什么短除法能求最小公倍数?
  7. macos 获取root权限
  8. c语言程序图像抠图,Opencv使用鼠标任意形状的抠图
  9. 云服务器与实体服务器性能,实体服务器和云服务器 的利与弊
  10. 解析十大网络防骗术 全面防范网络欺诈