天天看點

文檔線上預覽的實作

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

既然是WEB應用,進一步的需求是能夠線上檢視文檔,根據使用者需求可能不允許下載下傳,不允許列印文檔。這一點微軟的進階解決方案是使用RMS,能夠設定每個使用者的打開權限,是否列印等,要求必須是域内,而且隻管理Office檔案的權限,對txt,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);

        if (wordDocument != null) 

            wordDocument.ExportAsFixedFormat(paramExportFilePath, 

                    paramExportFormat, false, 

                    paramExportOptimizeFor, paramExportRange, paramStartPage, 

                    paramEndPage, paramExportItem, true, 

                    true, paramCreateBookmarks, true, 

                    true, false, 

                    ref paramMissing); 

        result = true; 

    } 

    finally 

        { 

            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(); 

    return result; 

}

/// 将excel文檔轉換成PDF格式 

public static bool ConvertExcel2Pdf(string sourcePath, string targetPath) 

    object missing = Type.Missing; 

    Excel.XlFixedFormatType targetType= Excel.XlFixedFormatType.xlTypePDF; 

    Excel.Application application = null; 

    Excel.Workbook workBook = null; 

        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, true, false, missing, missing, missing, missing); 

    catch 

        result = false; 

        if (workBook != null) 

            workBook.Close(true, missing, missing); 

            workBook = null; 

        if (application != null) 

            application.Quit(); 

            application = null; 

/// 将ppt文檔轉換成PDF格式 

public static bool ConvertPowerPoint2Pdf(string sourcePath, string targetPath) 

    PowerPoint.PpSaveAsFileType targetFileType= PowerPoint.PpSaveAsFileType.ppSaveAsPDF; 

    PowerPoint.Application application = null; 

    PowerPoint.Presentation persentation = null; 

        application = new PowerPoint.Application(); 

        persentation = application.Presentations.Open(sourcePath, MsoTriState.msoTrue, MsoTriState.msoFalse, MsoTriState.msoFalse); 

        persentation.SaveAs(targetPath, targetFileType, MsoTriState.msoTrue);

        if (persentation != null) 

            persentation.Close(); 

            persentation = null; 

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

       /// 将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; 

       } 

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; 

        }

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

/// 添加水印 

/// <param name="inputPath">源PDF檔案路徑</param> 

/// <param name="outputPath">加水印後的PDF路徑</param> 

/// <param name="watermarkPath">水印圖檔的路徑</param> 

/// <param name="error"></param> 

public static bool AddWatermark(string inputPath, string outputPath, string watermarkPath, ref string error) 

        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(10, 10); 

        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; 

前面已經統一轉換為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中添加參數即可:

pdf