1. 程式人生 > >pdf2htmlEX實現pdf轉html

pdf2htmlEX實現pdf轉html

首先要感謝pdf2htmlEX的作者Lu Wang,該軟體是一個pdf轉html的開源軟體,效果非常理想。下面兩張圖片是html和pdf檢視下的截圖:




本人開發的一個功能:文件線上閱讀,要求能夠支援移動終端瀏覽器線上閱讀。考慮過將文件先轉pdf,然後在將pdf轉swf,利用flexpaper在前端瀏覽器訪問。但是由於safari瀏覽器不支援flash,所以這種方式不太適合。也測試過火狐的pdf.js,但是這個框架在safari中出現中文亂碼,同樣不行。最後,經過測試,只有使用pdf2htmlEX轉的html在各個瀏覽器上展示效果均不錯,所以選擇該軟體。

第一步:下載pdf2html。

第二步:修改pdf2html自帶的js檔案pdf2htmlEX.min.js。原因:移動終端瀏覽器對CSS定位absolute的支援有問題(不會出現滾動條),所以需要為所有頁面的容器設定高度,這樣,手機瀏覽器就可以出現滾動條了。修改和新增的js程式碼如下:

檔案最後加上:
window.onload=function(){
	var eles = document.getElementsByClassName('pf w0 h0');
	var height = 0;
	for(var i=0,len=eles.length;i<len;i++){
		height +=eles[i].scrollHeight+20;
	}
	if(height>0)
	document.getElementById('page-container').style.height=height+'px';
}
/*註釋下面這段程式碼,因為手機瀏覽器無法觸發滾動事件
    this.container.addEventListener('scroll', function() {
      self.update_page_idx();
      self.schedule_render(true);
   }, false);
*/
/*新增,使用document物件上滾動載入頁面資料,這樣可以相容手機瀏覽器*/
document.addEventListener('scroll', function() {
        self.update_page_idx();
        self.schedule_render(true);
      }, false);

第三步:編寫java處理類
public class Pdf2htmlEXUtil {

	/**
	 * 呼叫pdf2htmlEX將pdf檔案轉換為html檔案
	 * @param command 呼叫exe的字串
	 * @param pdfName 需要轉換的pdf檔名稱
	 * @param htmlName 生成的html檔名稱
	 * @return
	 */
	public static boolean pdf2html(String command,String pdfName,String htmlName){
		Runtime rt = Runtime.getRuntime();
		try {
			Process p = rt.exec(command);
			StreamGobbler errorGobbler = new StreamGobbler(p.getErrorStream(), "ERROR");              
		      // kick off stderr  
		    errorGobbler.start();  
		    StreamGobbler outGobbler = new StreamGobbler(p.getInputStream(), "STDOUT");  
		      // kick off stdout  
		    outGobbler.start(); 
			int w = p.waitFor();
			System.out.println(w);
			int v = p.exitValue();
			System.out.println(v);
			return true;
		} catch (Exception e) {
			e.printStackTrace();
		}
		return false;
	}
	
	public static void main(String[] args) {
		pdf2html("D:\\pdf2htmlEX-v1.0\\pdf2htmlEX.exe D:\\v.pdf hello.html","v.pdf","v2.html");
	}
}
處理Runtime.exec()一直阻塞的類:如果沒有這個類,p.waitFor()將會一直等待,這是從這裡找到的解決方法
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;

/**
 * 用於處理Runtime.getRuntime().exec產生的錯誤流及輸出流
 * @author shaojing
 *
 */
public class StreamGobbler extends Thread {
	InputStream is;
	String type;
	OutputStream os;
	    
	StreamGobbler(InputStream is, String type) {
		this(is, type, null);
	}

    StreamGobbler(InputStream is, String type, OutputStream redirect) {
        this.is = is;
        this.type = type;
        this.os = redirect;
    }
    
    public void run() {
        InputStreamReader isr = null;
        BufferedReader br = null;
        PrintWriter pw = null;
        try {
            if (os != null)
                pw = new PrintWriter(os);
            isr = new InputStreamReader(is);
            br = new BufferedReader(isr);
            String line=null;
            while ( (line = br.readLine()) != null) {
                if (pw != null)
                    pw.println(line);
                System.out.println(type + ">" + line);    
            }
            if (pw != null)
                pw.flush();
        } catch (IOException ioe) {
            ioe.printStackTrace();  
        } finally{
        	try {
        		if(pw!=null)
        			pw.close();
        		if(br!=null)
        			br.close();
        		if(isr!=null)
        			isr.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
        }
    }
} 
一個完整的高保真pdf轉html例子就完成了。使用pdf2html,本人摸索了2天,終於在今天搞定,特此記錄一下。

pdf2html命令用法:

用法: pdf2htmlEX [options] <input.pdf> [<output.html>]
  -f,--first-page <int>         需要轉換的起始頁 (預設: 1)
  -l,--last-page <int>          需要轉換的最後一頁 (預設: 2147483647)
  --zoom <fp>                   縮放比例
  --fit-width <fp>              適合寬度 <fp> 畫素
  --fit-height <fp>             適合高度 <fp> 畫素
  --use-cropbox <int>           使用剪下框 (default: 1)
  --hdpi <fp>                   影象水平解析度 (default: 144)
  --vdpi <fp>                   影象垂直解析度 (default: 144)
  --embed <string>              指定哪些元素應該被嵌入到輸出
  --embed-css <int>             將CSS檔案嵌入到輸出中 (default: 1)
  --embed-font <int>            將字型檔案嵌入到輸出中 (default: 1)
  --embed-image <int>           將圖片檔案嵌入到輸出中 (default: 1)
  --embed-javascript <int>      將javascript檔案嵌入到輸出中 (default: 1)
  --embed-outline <int>         將連結嵌入到輸出中 (default: 1)
  --split-pages <int>           將頁面分割為單獨的檔案 (default: 0)
  --dest-dir <string>           指定目標目錄 (default: ".")
  --css-filename <string>       生成的css檔案的檔名 (default: "")
  --page-filename <string>      分割的網頁名稱  (default:"")
  --outline-filename <string>   生成的連結檔名稱 (default:"")
  --process-nontext <int>       渲染圖行,文字除外 (default: 1)
  --process-outline <int>       在html中顯示連結 (default: 1)
  --printing <int>              支援列印 (default: 1)
  --fallback <int>              在備用模式下輸出 (default: 0)
  --embed-external-font <int>   嵌入區域性匹配的外部字型 (default: 1)
  --font-format <string>        嵌入的字型檔案字尾 (ttf,otf,woff,svg) (default: "woff")
  --decompose-ligature <int>    分解連字-> fi (default:0)
  --auto-hint <int>             使用fontforge的autohint上的字型時不提示 (default: 0)
  --external-hint-tool <string> 字型外部提示工具 (overrides --auto-hint) (default: "")
  --stretch-narrow-glyph <int>  伸展狹窄的字形,而不是填充 (default: 0)
  --squeeze-wide-glyph <int>    收縮較寬的字形,而不是截斷 (default: 1)
  --override-fstype <int>       clear the fstype bits in TTF/OTF fonts (default:0)
  --process-type3 <int>         convert Type 3 fonts for web (experimental) (default: 0)
  --heps <fp>                   合併文字的水平臨界值,單位:畫素(default: 1)
  --veps <fp>                   vertical threshold for merging text, in pixels (default: 1)
  --space-threshold <fp>        斷字臨界值 (臨界值 * em) (default:0.125)
  --font-size-multiplier <fp>   一個大於1的值增加渲染精度 (default: 4)
  --space-as-offset <int>       把空格字元作為偏移量 (default: 0)
  --tounicode <int>             如何處理ToUnicode的CMap (0=auto, 1=force,-1=ignore) (default: 0)
  --optimize-text <int>         儘量減少用於文字的HTML元素的數目 (default: 0)
  --bg-format <string>          指定背景影象格式 (default: "png")
  -o,--owner-password <string>  所有者密碼 (為了加密檔案)
  -u,--user-password <string>   使用者密碼 (為了加密檔案)
  --no-drm <int>                覆蓋文件的 DRM 設定 (default: 0)
  --clean-tmp <int>             轉換後刪除臨時檔案 (default: 1)
  --data-dir <string>           指定的資料目錄 (default: ".\share\pdf2htmlEX")
  --debug <int>                 列印除錯資訊 (default: 0)
  -v,--version                  列印版權和版本資訊
  -h,--help                     列印使用幫助資訊


本人使用的版本時v0.11的和v1的版本有一些區別,主要是作者重新編寫了pdftohtmlEX.js所以需要對照上面的js做相應修改

window.onload=function(){
	var eles = document.getElementsByClassName('pd w0 h0');
	var height = 0;
	for(var i=0,len=eles.length;i<len;i++){
		height +=eles[i].scrollHeight+20;
	}
	if(height>0){
		document.getElementById('page-container').style.height=height+'px';
		document.getElementById('page-container').style.overflow='hidden';
	}
}

 //this.$container.scroll(function(){ _.schedule_render(); });
	  $(document).scroll(function(){_.schedule_render();});
修改之後的Pdf2htmlEXUtil
package cn.com.oims.util;

import cn.com.oims.config.BaseConfig;

/**@author liuzhengyong
 * @version 1.0 時間:2013-12-30  下午2:24:10
 * pdf檔案轉html工具類
 */
public class Pdf2htmlEXUtil {
private static final int OS = 2;
	/**
	 * 呼叫pdf2htmlEX將pdf檔案轉換為html檔案
	 * @param exeFilePath pdf2htmlEX.exe檔案路徑
	 * @param pdfFile pdf檔案絕對路徑
	 * @param [destDir] 生成的html檔案存放路徑
	 * @param htmlName 生成的html檔名稱
	 * @return
	 */
	public static boolean pdf2html(String exeFilePath,String pdfFile,String destDir,String htmlFileName){
		if(OS==2){//linux
			return pdf2html_linux(htmlFileName, htmlFileName, htmlFileName);
		}
		if(!(exeFilePath!=null&&!"".equals(exeFilePath)
				&&pdfFile!=null&&!"".equals(pdfFile)
				&&htmlFileName!=null&&!"".equals(htmlFileName))){
			System.out.println("傳遞的引數有誤!");
			return false;
		}
		Runtime rt = Runtime.getRuntime();
		StringBuilder command = new StringBuilder();
		command.append(exeFilePath).append(" ");
		if(destDir!=null&&!"".equals(destDir.trim()))//生成檔案存放位置,需要替換檔案路徑中的空格
			command.append("--dest-dir ").append(destDir.replace(" ", "\" \"")).append(" ");
		command.append("--optimize-text 1 ");//儘量減少用於文字的HTML元素的數目 (default: 0)
		command.append("--zoom 1.4 ");
		command.append("--process-outline 0 ");//html中顯示連結:0——false,1——true
		command.append("--font-format woff ");//嵌入html中的字型字尾(default ttf) ttf,otf,woff,svg
		command.append(pdfFile.replace(" ", "\" \"")).append(" ");//需要替換檔案路徑中的空格
		if(htmlFileName!=null&&!"".equals(htmlFileName.trim())){
			command.append(htmlFileName);
			if(htmlFileName.indexOf(".html")==-1)
				command.append(".html");
		}
		try {
			System.out.println("Command:"+command.toString());
			Process p = rt.exec(command.toString());
			StreamGobbler errorGobbler = new StreamGobbler(p.getErrorStream(), "ERROR");              
		    //開啟螢幕標準錯誤流
		    errorGobbler.start();  
		    StreamGobbler outGobbler = new StreamGobbler(p.getInputStream(), "STDOUT");  
		    //開啟螢幕標準輸出流
		    outGobbler.start(); 
			int w = p.waitFor();
			int v = p.exitValue();
			if(w==0&&v==0){
				return true;
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return false;
	}
	
	public static boolean pdf2html_linux(String pdfFile,String destDir,String htmlFileName){
		if(!(pdfFile!=null&&!"".equals(pdfFile)
				&&htmlFileName!=null&&!"".equals(htmlFileName))){
			System.out.println("傳遞的引數有誤!");
			return false;
		}
		Runtime rt = Runtime.getRuntime();
		StringBuilder command = new StringBuilder();
		command.append("pdf2htmlEX").append(" ");
		if(destDir!=null&&!"".equals(destDir.trim()))//生成檔案存放位置,需要替換檔案路徑中的空格
			command.append("--dest-dir ").append(destDir.replace(" ", "\" \"")).append(" ");
		command.append("--optimize-text 1 ");//儘量減少用於文字的HTML元素的數目 (default: 0)
		command.append("--process-outline 0 ");//html中顯示連結:0——false,1——true
		command.append("--font-format woff ");//嵌入html中的字型字尾(default ttf) ttf,otf,woff,svg
		command.append(pdfFile.replace(" ", "\" \"")).append(" ");//需要替換檔案路徑中的空格
		if(htmlFileName!=null&&!"".equals(htmlFileName.trim())){
			command.append(htmlFileName);
			if(htmlFileName.indexOf(".html")==-1)
				command.append(".html");
		}
		try {
			System.out.println("Command:"+command.toString());
			Process p = rt.exec(command.toString());
			StreamGobbler errorGobbler = new StreamGobbler(p.getErrorStream(), "ERROR");              
		    //開啟螢幕標準錯誤流
		    errorGobbler.start();  
		    StreamGobbler outGobbler = new StreamGobbler(p.getInputStream(), "STDOUT");  
		    //開啟螢幕標準輸出流
		    outGobbler.start(); 
			int w = p.waitFor();
			int v = p.exitValue();
			if(w==0&&v==0){
				return true;
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return false;
	}
}

在dos環境下的呼叫命名:

D:\\pdf2htmlEX-v1.0\\pdf2htmlEX.exe d:\\test" "2 D:\\test" "1\\v1.pdf [v3.html]
D:\\pdf2htmlEX-v1.0\\pdf2htmlEX.exe表示exe檔案路徑。後面的空格不能少
d:\\test" "2表示轉換之後的html存放位置,這裡的" "為空格,dos環境下,所有空格必須使用""包裹,否則不能識別。後面的空格不能少
D:\\test" "1\\v1.pdf表示pdf檔案的位置。後面的空格不能少
v3.html表示將pdf轉為html檔案的檔名。可選