Click here to Skip to main content
Click here to Skip to main content

ASP.NET PDF Viewer User Control Without Acrobat Reader Installed on Client or Server

By , 9 Sep 2012
 
PDFViewASP

Introduction

This article discusses how to create an ASP.NET PDF Viewer User Control that is not dependent on Acrobat software being installed.

Fundamental Concepts

  1. Get a page count of the PDF document that needs to be viewed to define your page number boundaries (PdfLibNet - XPDF) 
  2. Convert the PDF document (specific page on demand) to a raster image format (PdfLibNet - XPDF)  
  3. Convert the current page to be viewed into a PNG file
  4. Display the PNG file in an image on a web page 

Several utility classes were created or added from others which expose functionality needed from the various helper libraries.

  1. AFPDFLibUtil.vb (contains methods to create Bookmark HTML, Search, get page count, convert PDF to PNG)
  2. ImageUtil.vb (contains methods for image manipulation such as resize, rotation, conversion, etc.)
  3. ASPPDFLib.vb (contains generic wrapper functions that call specific technologies)
  4. PDFViewer.ascx.vb (contains code behind for the PDF Viewer User Control)
  5. PDFViewer.ascx (contains client side HTML/JavaScript for the PDF Viewer User Control)

Using the Code 

ASP Server Configuration Requirements

  • You must give the ASPNET user (IISUSR or ASPNET or Network services user) permission to modify (read/write) the /PDF and /render directories.
  • You must give the ASPNET user (IISUSR or ASPNET or Network services user) permission to  Read & Execute the /bin diirectory.
  • The DLL PDFLibNet.dll must be available to the page. You might have to register it with the GAC depending on your operating system to make it available to the application.
  • PDFLibNet.dll and PDFLibCmdLine.exe must both be compiled with the same architecture (x86 or x64) 
  • If x86 is used, you must set the advanced settings of the AppPool to allow execution of 32-bit applications if you are on a 64-bit OS.  

This project consists of 3 DLLs that must all be in the same directory:

  • PDFLibNET.dll
  • StatefullScrollPanel.dll
  • PDFViewASP.dll

To place a PDF Viewer User Control on a web page:   

<uc1:PDFViewer ID="PDFViewer1" runat="server" /> 

Set the FileName property to view the PDF file in the code behind:

      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

The essential part of this solution is extracting the current page to be viewed from a PDF file. Since we are using ASP.NET, I chose to implement a file based solution to avoid memory management issues when trying to persist PDF byte streams for multiple clients. I chose to extract a page from PDF using PDFLibNet and store it to the File System as a PNG image. I chose PNG since it uses ZIP compression which results in a lossless compressed image and small file size.

    '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

In the PDFViewer code, a page number is specified and:

  • The page is loaded from the PDF file and converted to a PNG file.
  • We add the PNG file name to the ASP.NET Cache with an expiration of 5 minutes to ensure that we don't leave rendered images lying around on the server.
  • The ImageUrl is updated with the path to the PNG file.

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

Points of Interest

This project was made possible due to various open source libraries that others were kind enough to distribute freely. I would like to thank the PDFLibNet developer Antonio Sandoval and Foo Labs (XPDF) for their efforts.

History

  • 1.0 - Initial version
  • 1.1 - Added Search capabilities, reduced DLL dependencies, made PDF subsystem use XPDF only
  • 1.2 - Replaced PDFLibNet.dll to fix incorrect configuration error 0x800736B1
  • 1.3 - Optimized search routines
  • 1.4 - Remove outdated links to legacy content
  • 1.5 - Updated permissions information

License

This article, along with any associated source code and files, is licensed under The GNU General Public License (GPLv3)

About the Author

Ron Schuler
Software Developer
United States United States
Member
No Biography provided

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
Hint: For improved responsiveness ensure Javascript is enabled and choose 'Normal' from the Layout dropdown and hit 'Update'.
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
QuestionCan We Print this PDF Document with print dialog boxmemberPraveenGajawada21 Apr '13 - 21:23 
QuestionArabic Fontsmembermon8127 Jan '13 - 19:32 
QuestionCan you help me to create pdf editormemberSMayur19 Jan '13 - 2:40 
AnswerRe: Can you help me to create pdf editormvpadriancs20 May '13 - 16:41 
QuestionC# code for thismemberaravindnass1 Dec '12 - 18:24 
Questionhow to download the code for this articlemembervinaykd198121 Nov '12 - 1:08 
AnswerRe: how to download the code for this articlememberzmmkele29 Nov '12 - 16:17 
Questionprotected pdf Not working....memberGaurav12214 Nov '12 - 2:27 
AnswerRe: protected pdf Not working....memberDadajiIn30 Nov '12 - 18:37 
QuestionHow to integrate this code in Asp.Net MVC ?memberSachin Panchal30 Oct '12 - 23:55 
GeneralMy vote of 5memberSavalia Manoj M29 Oct '12 - 1:39 
Questionprotected pdf problemgroupivanruisoto23 Sep '12 - 23:36 
QuestionForm FieldsmemberMike Stiles14 Sep '12 - 11:53 
GeneralMy vote of 5memberAnurag Gandhi11 Sep '12 - 3:16 
QuestionC# version of PDF viewermemberk.sathishkumar10 Sep '12 - 22:18 
GeneralMy vote of 5memberFarhan Ghumra10 Sep '12 - 19:30 
QuestionNot working with Online Server Databasemembersanju ahuja9 Sep '12 - 7:48 
QuestionPDF Viewer not working when impersonate = truememberpandiarajan198610 Aug '12 - 0:10 
Questionpdf viewermemberslamet supriyadi2 Aug '12 - 20:18 
QuestionAttempted to read or write protected memory. This is often an indication that other memory is corrupt.memberrabbwhite24 Jul '12 - 22:52 
Questionpassword problemmemberDonCreAtive20 Jul '12 - 3:46 
AnswerRe: password problemmemberkumargtl8 Aug '12 - 1:36 
GeneralRe: password problemmemberMohammedHabeeb8 Sep '12 - 21:31 
GeneralRe: password problemmemberRon Schuler9 Sep '12 - 4:27 
QuestionAgian , help me : System.Runtime.InteropServices.ExternalExceptionmemberreza_project12 Jun '12 - 18:34 
QuestionAccess is denied, please help!memberbehzad200024 Apr '12 - 9:51 
AnswerRe: Access is denied, please help!memberbehzad20008 May '12 - 0:51 
QuestionLicensing?membersdas00715 Mar '12 - 3:18 
AnswerRe: Licensing?memberRon Schuler15 Mar '12 - 14:54 
AnswerRe: Licensing?memberkumargtl8 Aug '12 - 3:02 
GeneralRe: Licensing?memberRon Schuler8 Aug '12 - 3:07 
QuestionClinet side PDF rendering in HTML5membercodeivan9 Mar '12 - 12:49 
AnswerRe: Clinet side PDF rendering in HTML5memberRon Schuler9 Mar '12 - 15:04 
QuestionASP.NET PDF Viewer User Control Without Acrobat Reader Installed on Client or Servermembermunish199016 Feb '12 - 23:28 
AnswerRe: ASP.NET PDF Viewer User Control Without Acrobat Reader Installed on Client or ServermemberVibs18 Jun '12 - 0:52 
QuestionWin32Exception (0x80004005): The system cannot find the path specifiedmemberRodrigo Galvao28 Dec '11 - 2:35 
AnswerRe: Win32Exception (0x80004005): The system cannot find the path specifiedmemberbehzad20008 May '12 - 0:48 
QuestionUnicode Bookmarkmemberreza_project27 Dec '11 - 19:56 
QuestionYou Rock!!!memberMember 83893565 Dec '11 - 15:36 
QuestionHelp mememberreza_project29 Nov '11 - 0:36 
AnswerRe: Help mememberRon Schuler29 Nov '11 - 6:49 
QuestionTHE SAME WORKING IN LOCAL BUT NOT IN SERVERmemberMember 774197425 Oct '11 - 2:41 
Bugcan not work under iis 7.5 server2008 r2 64bitmemberranzige14 Oct '11 - 22:55 
GeneralRe: can not work under iis 7.5 server2008 r2 64bitmemberRon Schuler9 Sep '12 - 4:24 
QuestionNew version in SVN repositorymemberRon Schuler11 Aug '11 - 3:14 
AnswerRe: New version in SVN repositorymemberSai_U27 Oct '11 - 18:40 
QuestionUpdate progress ...memberRon Schuler7 Aug '11 - 13:59 
Generalpdf 400mb not openingmemberGuru Prasath N7 Aug '11 - 8:55 
GeneralRe: pdf 400mb not openingmemberRon Schuler7 Aug '11 - 14:01 
GeneralRe: pdf 400mb not openingmemberraveeshdadheech11 Nov '11 - 21:42 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web01 | 2.6.130516.1 | Last Updated 9 Sep 2012
Article Copyright 2009 by Ron Schuler
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid