天天看点

文档在线预览的实现

最近在研究企业文档管理,这个是基本上所有企业都需要的软件,当然也是有很多种解决方案。对于企业文档来说,最基本的需求就是独立存储,共享。这种需求只需要建立一个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