Visual Basic.NET 7.x (2002/03)Visual Basic 10Visual Basic 9 (2008)Visual Basic 8 (2005)Visual Basic 6.NET 2.0中级Dev.NETVisual BasicASP.NET
ASP.NET PDF 查看器用户控件,无需在客户端或服务器上安装 Acrobat Reader






4.77/5 (71投票s)
ASP.NET PDF 文档查看器控件,无需安装任何 Acrobat 产品

引言
本文讨论了如何创建一个 ASP.NET PDF 查看器用户控件,该控件不依赖于安装 Acrobat 软件。
基本概念
- 获取需要查看的 PDF 文档的页面计数,以定义您的页码边界 (PdfLibNet - XPDF)
- 将 PDF 文档(按需特定页面)转换为光栅图像格式 (PdfLibNet - XPDF)
- 将当前页面转换为 PNG 文件
- 在网页上的图像中显示 PNG 文件
创建或从其他地方添加了几个实用程序类,这些类公开了各种辅助库所需的功能。
- AFPDFLibUtil.vb(包含创建书签 HTML、搜索、获取页面计数、将 PDF 转换为 PNG 的方法)
- ImageUtil.vb(包含图像操作方法,例如调整大小、旋转、转换等)
- ASPPDFLib.vb(包含调用特定技术的通用包装函数)
- PDFViewer.ascx.vb(包含 PDF 查看器用户控件的后台代码)
- PDFViewer.ascx(包含 PDF 查看器用户控件的客户端 HTML/JavaScript)
使用代码
ASP 服务器配置要求
- 您必须授予 ASPNET 用户(IISUSR 或 ASPNET 或网络服务用户)修改(读/写)/PDF 和 /render 目录的权限。
- 您必须授予 ASPNET 用户(IISUSR 或 ASPNET 或网络服务用户)读取和执行 /bin 目录的权限。
- DLL PDFLibNet.dll 必须对页面可用。根据您的操作系统,您可能需要使用 GAC 注册它,以使其对应用程序可用。
- PDFLibNet.dll 和 PDFLibCmdLine.exe 必须使用相同的架构(x86 或 x64)进行编译
- 如果使用 x86,您必须设置 AppPool 的高级设置以允许执行 32 位应用程序(如果您使用的是 64 位操作系统)。
此项目包含 3 个 DLL,它们都必须位于同一目录下
- PDFLibNET.dll
- StatefullScrollPanel.dll
- PDFViewASP.dll
要在网页上放置 PDF 查看器用户控件:
<uc1:PDFViewer ID="PDFViewer1" runat="server" />
设置 FileName
属性以在后台代码中查看 PDF 文件
Dim pdfFileName As String = Request.MapPath("PDF") & "\" & "myPDF.pdf"
If ImageUtil.IsPDF(pdfFileName) Then
ErrorLabel.Visible = False
PDFViewer1.FileName = pdfFileName
Else
ErrorLabel.Text = "Only PDF files (*.pdf) are allowed to be viewed."
ErrorLabel.Visible = True
End If
此解决方案的本质部分是从 PDF 文件中提取要查看的当前页面。由于我们使用的是 ASP.NET,我选择实现一个基于文件的解决方案,以避免在尝试为多个客户端保留 PDF 字节流时出现内存管理问题。我选择使用 PDFLibNet 从 PDF 中提取页面,并将其作为 PNG 图像存储到文件系统中。我选择了 PNG,因为它使用 ZIP 压缩,这会产生无损压缩图像和较小的文件大小。
'Modified for ASP usage
Public Shared Function GetPageFromPDF(ByVal filename As String, _
ByVal destPath As String, ByRef PageNumber As Integer, _
Optional ByVal DPI As Integer = RENDER_DPI, _
Optional ByVal Password As String = "", _
Optional ByVal searchText As String = "", _
Optional ByVal searchDir As SearchDirection = 0) As String
GetPageFromPDF = ""
Dim pdfDoc As New PDFLibNet.PDFWrapper
pdfDoc.RenderDPI = 72
pdfDoc.LoadPDF(filename)
If Not Nothing Is pdfDoc Then
pdfDoc.CurrentPage = PageNumber
pdfDoc.SearchCaseSensitive = False
Dim searchResults As New List(Of PDFLibNet.PDFSearchResult)
If searchText <> "" Then
Dim lFound As Integer = 0
If searchDir = SearchDirection.FromBeginning Then
lFound = pdfDoc.FindFirst(searchText, _
PDFLibNet.PDFSearchOrder.PDFSearchFromdBegin, False, False)
ElseIf searchDir = SearchDirection.Forwards Then
lFound = pdfDoc.FindFirst(searchText, _
PDFLibNet.PDFSearchOrder.PDFSearchFromCurrent, False, False)
ElseIf searchDir = SearchDirection.Backwards Then
lFound = pdfDoc.FindFirst(searchText, _
PDFLibNet.PDFSearchOrder.PDFSearchFromCurrent, True, False)
End If
If lFound > 0 Then
If searchDir = SearchDirection.FromBeginning Then
PageNumber = pdfDoc.SearchResults(0).Page
searchResults = GetAllSearchResults(filename, searchText, PageNumber)
ElseIf searchDir = SearchDirection.Forwards Then
If pdfDoc.SearchResults(0).Page > PageNumber Then
PageNumber = pdfDoc.SearchResults(0).Page
searchResults = GetAllSearchResults(filename, searchText, PageNumber)
Else
searchResults = SearchForNextText(filename, searchText, _
PageNumber, searchDir)
If searchResults.Count > 0 Then
PageNumber = searchResults(0).Page
End If
End If
ElseIf searchDir = SearchDirection.Backwards Then
If pdfDoc.SearchResults(0).Page < PageNumber Then
PageNumber = pdfDoc.SearchResults(0).Page
searchResults = GetAllSearchResults(filename, searchText, PageNumber)
Else
searchResults = SearchForNextText(filename, searchText, _
PageNumber, searchDir)
If searchResults.Count > 0 Then
PageNumber = searchResults(0).Page
End If
End If
End If
End If
End If
Dim outGuid As Guid = Guid.NewGuid()
Dim output As String = destPath & "\" & outGuid.ToString & ".png"
Dim pdfPage As PDFLibNet.PDFPage = pdfDoc.Pages(PageNumber)
Dim bmp As Bitmap = pdfPage.GetBitmap(DPI, True)
bmp.Save(output, System.Drawing.Imaging.ImageFormat.Png)
bmp.Dispose()
GetPageFromPDF = output
If searchResults.Count > 0 Then
GetPageFromPDF = HighlightSearchCriteria(output, DPI, searchResults)
End If
pdfDoc.Dispose()
End If
End Function
在 PDFViewer 代码中,指定了一个页码,并且
- 从 PDF 文件中加载页面并将其转换为 PNG 文件。
- 我们将 PNG 文件名添加到 ASP.NET 缓存中,有效期为 5 分钟,以确保我们不会在服务器上留下渲染后的图像。
- 使用 PNG 文件的路径更新
ImageUrl
。
PDFViewer.ascx.vb
Private Sub DisplayCurrentPage(Optional ByVal doSearch As Boolean = False)
'Set how long to wait before deleting the generated PNG file
Dim expirationDate As DateTime = Now.AddMinutes(5)
Dim noSlide As TimeSpan = System.Web.Caching.Cache.NoSlidingExpiration
Dim callBack As New CacheItemRemovedCallback(AddressOf OnCacheRemove)
ResizePanels()
CheckPageBounds()
UpdatePageLabel()
InitBookmarks()
Dim destPath As String = Request.MapPath("render")
Dim indexNum As Integer = (parameterHash("CurrentPageNumber") - 1)
Dim numRotation As Integer = parameterHash("RotationPage")(indexNum)
Dim imageLocation As String
If doSearch = False Then_
imageLocation = ASPPDFLib.GetPageFromPDF(parameterHash("PDFFileName"), _
destPath, parameterHash("CurrentPageNumber"), parameterHash("DPI"), _
parameterHash("Password"), numRotation)
Else
imageLocation = ASPPDFLib.GetPageFromPDF(parameterHash("PDFFileName"), destPath _
, parameterHash("CurrentPageNumber") _
, parameterHash("DPI") _
, parameterHash("Password") _
, numRotation, parameterHash("SearchText") _
, parameterHash("SearchDirection") _
)
UpdatePageLabel()
End If
ImageUtil.DeleteFile(parameterHash("CurrentImageFileName"))
parameterHash("CurrentImageFileName") = imageLocation
'Add full filename to the Cache with an expiration
'When the expiration occurs, it will call OnCacheRemove which will delete the file
Cache.Insert(New Guid().ToString & "_DeleteFile", imageLocation, _
Nothing, expirationDate, noSlide, _
System.Web.Caching.CacheItemPriority.Default, callBack)
Dim matchString As String = _
Request.MapPath("").Replace("\", "\\") ' escape backslashes
CurrentPageImage.ImageUrl = Regex.Replace(imageLocation, matchString & "\\", "~/")
End Sub
Private Sub OnCacheRemove(ByVal key As String, ByVal val As Object, _
ByVal reason As CacheItemRemovedReason)
If Regex.IsMatch(key, "DeleteFile") Then
ImageUtil.DeleteFile(val)
End If
End Sub
ASPPDFLib.vb
Public Shared Function GetPageFromPDF(ByVal sourceFileName As String _
, ByVal destFolderPath As String _
, ByRef iPageNumber As Integer _
, Optional ByVal DPI As Integer = 0 _
, Optional ByVal password As String = "" _
, Optional ByVal rotations As Integer = 0 _
, Optional ByVal searchText As String = "" _
, Optional ByVal searchDir As Integer = _
AFPDFLibUtil.SearchDirection.FromBeginning _
) As String
GetPageFromPDF = AFPDFLibUtil.GetPageFromPDF(sourceFileName, _
destFolderPath, iPageNumber, DPI, password, searchText, searchDir)
ImageUtil.ApplyRotation(GetPageFromPDF, rotations)
End Function
关注点
由于其他人慷慨地自由分发的各种开源库,这个项目才得以实现。 我要感谢 PDFLibNet 的开发者 Antonio Sandoval 和 Foo Labs (XPDF) 他们的努力。
历史
- 1.0 - 初始版本
- 1.1 - 增加了搜索功能,减少了 DLL 依赖项,使 PDF 子系统仅使用 XPDF
- 1.2 - 替换了 PDFLibNet.dll 以修复不正确的配置错误 0x800736B1
- 1.3 - 优化搜索例程
- 1.4 - 移除过时的指向旧内容链接
- 1.5 - 更新权限信息