文件線上預覽的實現

深藍發表於2016-03-30

最近在研究企業文件管理,這個是基本上所有企業都需要的軟體,當然也是有很多種解決方案。對於企業文件來說,最基本的需求就是獨立儲存,共享。這種需求只需要建立一個Windows共享資料夾或者架一個Samba伺服器即可實現,無法做複雜的許可權管理,統計等。另一種方案就是架一個Web應用,比如SharePoint,就可以實現。

既然是WEB應用,進一步的需求是能夠線上檢視文件,根據使用者需求可能不允許下載,不允許列印文件。這一點微軟的高階解決方案是使用RMS,能夠設定每個使用者的開啟許可權,是否列印等,要求必須是域內,而且只管理Office檔案的許可權,對txt,pdf就沒辦法了。另外一個解決方案是線上文件預覽,使用者在網頁中檢視文件內容,使用者無需拿到原始文件,如果有許可權的話,可以允許使用者下載文件。這就就是百度文庫,豆丁之類的網站的功能。下面來說說怎麼實現。

1.文件統一轉換為pdf

這裡的文件我們要看是什麼格式,不同的格式有不同的轉換方法。

1.1 Office文件轉換pdf

對於Office文件(Word,Excel,PowerPoint),那麼可以呼叫Office提供的COM介面,把文件另存為PDF。這個要求伺服器上必須安裝Office,同時要注意許可權,不然很容易導致在本地除錯時可以轉換為PDF,但是一旦部署到伺服器上去就不行。另外還需要注意的是,如果Office轉換pdf時發生異常,可能導致Office的程式駐留在伺服器,不斷駐留Office程式會導致伺服器資源耗盡。

這是Office文件轉換為pdf的程式碼:

/// <summary> 
/// 將word文件轉換成PDF格式 
/// </summary> 
/// <param name="sourcePath"></param> 
/// <param name="targetPath"></param> 
/// <returns></returns> 
public static bool ConvertWord2Pdf(string sourcePath, string targetPath) 

    bool result; 
    Word.WdExportFormat exportFormat= Word.WdExportFormat.wdExportFormatPDF; 
    object paramMissing = Type.Missing; 
    Word.Application wordApplication = new Word.Application(); 
    Word.Document wordDocument = null
    try 
    { 
        object paramSourceDocPath = sourcePath; 
        string paramExportFilePath = targetPath;
        Word.WdExportFormat paramExportFormat = exportFormat; 
        Word.WdExportOptimizeFor paramExportOptimizeFor = 
                Word.WdExportOptimizeFor.wdExportOptimizeForPrint; 
        Word.WdExportRange paramExportRange = Word.WdExportRange.wdExportAllDocument; 
        int paramStartPage = 0
        int paramEndPage = 0
        Word.WdExportItem paramExportItem = Word.WdExportItem.wdExportDocumentContent; 
        Word.WdExportCreateBookmarks paramCreateBookmarks = 
                Word.WdExportCreateBookmarks.wdExportCreateWordBookmarks; 
    
        wordDocument = wordApplication.Documents.Open( 
                ref paramSourceDocPath, ref paramMissing, ref paramMissing, 
                ref paramMissing, ref paramMissing, ref paramMissing, 
                ref paramMissing, ref paramMissing, ref paramMissing, 
                ref paramMissing, ref paramMissing, ref paramMissing, 
                ref paramMissing, ref paramMissing, ref paramMissing, 
                ref paramMissing);
        if (wordDocument != null
            wordDocument.ExportAsFixedFormat(paramExportFilePath, 
                    paramExportFormat, false
                    paramExportOptimizeFor, paramExportRange, paramStartPage, 
                    paramEndPage, paramExportItem, true
                    true, paramCreateBookmarks, true
                    truefalse
                    ref paramMissing); 
        result = true
    } 
    finally 
    { 
        if (wordDocument != null
        { 
            wordDocument.Close(ref paramMissing, ref paramMissing, ref paramMissing); 
            wordDocument = null
        } 
        if (wordApplication != null
        { 
            wordApplication.Quit(ref paramMissing, ref paramMissing, ref paramMissing); 
            wordApplication = null
        } 
        GC.Collect(); 
        GC.WaitForPendingFinalizers(); 
        GC.Collect(); 
        GC.WaitForPendingFinalizers(); 
    } 
    return result; 
}
/// <summary> 
/// 將excel文件轉換成PDF格式 
/// </summary> 
/// <param name="sourcePath"></param> 
/// <param name="targetPath"></param> 
/// <returns></returns> 
public static bool ConvertExcel2Pdf(string sourcePath, string targetPath) 

    bool result; 
    object missing = Type.Missing; 
    Excel.XlFixedFormatType targetType= Excel.XlFixedFormatType.xlTypePDF; 
    Excel.Application application = null
    Excel.Workbook workBook = null
    try 
    { 
        application = new Excel.Application(); 
        object target = targetPath; 
        workBook = application.Workbooks.Open(sourcePath, missing, missing, missing, missing, missing, 
                missing, missing, missing, missing, missing, missing, missing, missing, missing);
        workBook.ExportAsFixedFormat(targetType, target, Excel.XlFixedFormatQuality.xlQualityStandard, truefalse, missing, missing, missing, missing); 
        result = true
    } 
    catch 
    { 
        result = false
    } 
    finally 
    { 
        if (workBook != null
        { 
            workBook.Close(true, missing, missing); 
            workBook = null
        } 
        if (application != null
        { 
            application.Quit(); 
            application = null
        } 
        GC.Collect(); 
        GC.WaitForPendingFinalizers(); 
        GC.Collect(); 
        GC.WaitForPendingFinalizers(); 
    } 
    return result; 
}
/// <summary> 
/// 將ppt文件轉換成PDF格式 
/// </summary> 
/// <param name="sourcePath"></param> 
/// <param name="targetPath"></param> 
/// <returns></returns> 
public static bool ConvertPowerPoint2Pdf(string sourcePath, string targetPath) 

    bool result; 
    PowerPoint.PpSaveAsFileType targetFileType= PowerPoint.PpSaveAsFileType.ppSaveAsPDF; 
    PowerPoint.Application application = null
    PowerPoint.Presentation persentation = null
    try 
    { 
        application = new PowerPoint.Application(); 
        persentation = application.Presentations.Open(sourcePath, MsoTriState.msoTrue, MsoTriState.msoFalse, MsoTriState.msoFalse); 
        persentation.SaveAs(targetPath, targetFileType, MsoTriState.msoTrue);
        result = true
    } 
    catch 
    { 
        result = false
    } 
    finally 
    { 
        if (persentation != null
        { 
            persentation.Close(); 
            persentation = null
        } 
        if (application != null
        { 
            application.Quit(); 
            application = null
        } 
        GC.Collect(); 
        GC.WaitForPendingFinalizers(); 
        GC.Collect(); 
        GC.WaitForPendingFinalizers(); 
    } 
    return result; 

1.2 純文字轉換pdf

如果是文字需要轉換為PDF,我們可以使用iTextSharp這個元件,對於純文字,注意的是原始檔中沒有設定字型之類的,需要在轉換成PDF時指定字型,否則對於中文可能由於沒有設定字型而轉換不出來。

/// <summary> 
       
/// 將Txt轉換為PDF 
       
/// </summary> 
       
/// <param name="sourcePath"></param> 
       
/// <param name="targetPath"></param> 
       
/// <returns></returns> 
       public static bool ConvertText2Pdf(string sourcePath, string targetPath) 
       { 
           var text = FileHelper.ReadTextFile(sourcePath); 
           Document document = new Document(PageSize.A4);
           try 
           { 
               //step 2:建立一個writer用於監聽Document以及通過PDF-stream指向一個檔案  
               PdfWriter.GetInstance(document, new FileStream(targetPath, FileMode.Create)); 
               // step 3: 開啟document  
               document.Open();
               var f = GetFont(); 
               // step 4: 新增一段話到document中  
               document.Add(new Paragraph(text, f)); 
           } 
           catch (Exception ex) 
           { 
               return false
           } 
           finally 
           { 
               if (document.IsOpen()) 
                   // step 5: 關閉document  
                   document.Close(); 
           } 
           return true
       }
       private static Font GetFont() 
       { 
           var fontPath = (string) ConfigurationManager.AppSettings["FontPath"]; 
           if (string.IsNullOrEmpty(fontPath))//沒有指定字型就用楷體 
           { 
               var fontName = "楷體"
               if (!FontFactory.IsRegistered(fontName)) 
               { 
                   fontPath = Environment.GetFolderPath(Environment.SpecialFolder.Windows) + @"\Fonts\simkai.ttf"
                   FontFactory.Register(fontPath); 
               } 
               return FontFactory.GetFont(fontName, BaseFont.IDENTITY_H, BaseFont.EMBEDDED); 
           } 
           BaseFont bfChinese = BaseFont.CreateFont(fontPath,BaseFont.IDENTITY_H,BaseFont.NOT_EMBEDDED); 
           Font fontChinese = new Font(bfChinese, 16f, Font.NORMAL); 
           return fontChinese; 
       } 

1.3 HTML轉換pdf

HTML中包含的元素較多,比較複雜,主要有兩種方法,一種是呼叫瀏覽器的介面,讓瀏覽器把HTML列印為PDF,另外就是ITextSharp提供了專門的XML/HTML轉換元件:XML Worker,這個已經獨立出來,不包含在ITextSharp中,需要單獨下載。

public static bool ConvertHtml2Pdf(string text, string pdfPath) 
        { 
            Document document = new Document(PageSize.A4);
            try 
            { 
                PdfWriter.GetInstance(document, new FileStream(pdfPath, FileMode.Create)); 
                document.Open(); 
             
                var fontName = "楷體"
                if (!FontFactory.IsRegistered(fontName)) 
                { 
                    var fontPath = Environment.GetFolderPath(Environment.SpecialFolder.Windows) + @"\Fonts\simkai.ttf"
                    FontFactory.Register(fontPath); 
                } 
                var elements = iTextSharp.tool.xml.XMLWorkerHelper.ParseToElementList(text, @"body { 
    font-size: 16px; 
    color: #F00; 
    font-family: 楷體; 
}
"); 
                //iTextSharp.text. 
                foreach (var element in elements) 
                { 
                    document.Add(element); 
                }
            } 
            catch (DocumentException de) 
            { 
                Console.Error.WriteLine(de.Message); 
            } 
            catch (IOException ioe) 
            { 
                Console.Error.WriteLine(ioe.Message); 
            } 
            document.Close(); 
            return true
        }

1.4新增水印

以上都是轉換成pdf的功能,在轉換後,我們可以進一步使用ITextSharp對pdf進行加工,比較常見的新增水印功能。其實就是做一個淡淡的背景透明的圖片,然後開啟pdf檔案,在每一頁中畫上水印圖片即可。

/// <summary> 
/// 新增水印 
/// </summary> 
/// <param name="inputPath">源PDF檔案路徑</param> 
/// <param name="outputPath">加水印後的PDF路徑</param> 
/// <param name="watermarkPath">水印圖片的路徑</param> 
/// <param name="error"></param> 
/// <returns></returns> 
public static bool AddWatermark(string inputPath, string outputPath, string watermarkPath, ref string error) 

    try 
    { 
        PdfReader pdfReader = new PdfReader(inputPath); 
        int numberOfPages = pdfReader.NumberOfPages; 
        FileStream outputStream = new FileStream(outputPath, FileMode.Create); 
        PdfStamper pdfStamper = new PdfStamper(pdfReader, outputStream); 
        PdfContentByte waterMarkContent;
        iTextSharp.text.Image image = iTextSharp.text.Image.GetInstance(watermarkPath);
        image.SetAbsolutePosition(1010); 
        for (int i = 1; i <= numberOfPages; i++) 
        { 
            waterMarkContent = pdfStamper.GetUnderContent(i); 
            waterMarkContent.AddImage(image); 
        } 
        pdfStamper.Close(); 
        pdfReader.Close(); 
        outputStream.Close(); 
        return true
    } 
    catch (Exception ex) 
    { 
        error = ex.StackTrace; 
        return false
    } 

2.線上預覽pdf文件

前面已經統一轉換為pdf文件,接下來就是對pdf的線上預覽。這個在以前是不現實的,現在有了HTML5,只要瀏覽器支援HTML5就可以使用pdf.js庫,將伺服器上的pdf檔案轉換成HTML5程式碼展示在瀏覽器上。另外還有一個解決方案是使用Flash,需要把pdf檔案進一步轉換為swf檔案,然後由Flash播放器來播放這個文件。可惜Flash已經是一個過時即將淘汰的技術了,像iPad,iPhone就不支援Flash,所以使用HTML5才是更明智的選擇。

pdf.js網站已經提供了庫和示例,瀏覽頁面是http://mozilla.github.io/pdf.js/web/viewer.html,我們要開啟我們轉換的檔案,只需要在URL中新增引數即可:

/web/viewer.html?file=yourpdf.pdf
我們可以進一步修改viewer.html中的程式碼,根據需求去掉下載,列印等按鈕,禁止使用者下載和列印檔案。

相關文章