-
-
Notifications
You must be signed in to change notification settings - Fork 2.9k
Embedding PDF.JS in CEFSharp
aimcosoftware edited this page May 25, 2023
·
19 revisions
PDF.JS is Mozilla's open source PDF renderer, available here. The same one that is used in Firefox.
- Has a complete API for manipulating the viewer and PDF, accessible from javascript.
- All loaded from local HTML, CSS and JS files, so can be easily modified.
- Page navigation from the index is added to browser history
- Restores last scroll position when revisiting the document
- unzip pdf.js in a convenient folder for your project
- Add a sub folder to download and read PDFs
- Register the folder in a custom scheme handler
- Add javascript to post message when viewer loaded
- disable the default PDF extension in CEFSharp
- Disable default handling so PDFs trigger a download
- Use download and request handlers to trigger PDF handling
- Download PDF to sub folder of the custom scheme
- After
isComplete
, load PDF.JS viewer from custom scheme
The PDF.JS viewer is loaded with a query string of the local scheme url and PDF url e.g pdfjs://viewer/web/viewer.html?file=pdfjs://viewer/cache/pdffile.pdf&url=https://original.com/pdffile.pdf
.
The query parameter file is used by the viewer, url is used to provide the PDF url.
This means that on reload and history navigation, the PDF will be loaded from the custom scheme, as expected.
If you want to reload from the server, you would need to implement your own Reload(IgnoreCache)
method.
Example folder structure with cache folder added for PDF downloads:
build pdf.js code
cache add folder for PDFs
web pdf.js viewer
Friend PDFEnabled As Boolean
Friend PDFCachePath As String
Friend Sub RegisterPDFJS(ByRef Settings As CefSettings, RootPath As String)
'Disable default handling - PDFs will be downloaded
Settings.CefCommandLineArgs.Add("disable-pdf-extension")
Dim Scheme As New CefCustomScheme
Scheme.SchemeName = "pdfjs"
Scheme.DomainName = "viewer"
Scheme.SchemeHandlerFactory = New SchemeHandler.FolderSchemeHandlerFactory(RootPath)
Settings.RegisterScheme(Scheme)
PDFCachePath = $"{RootPath}\cache\"
PDFEnabled = True
End Sub
'Set download and request handlers
Browser.DownloadHandler = Me
Browser.RequestHandler = Me
' Locals to control PDF download and viewing
Private PDFCacheUrl As String = ""
Private PDFSavePath As String = ""
Private Sub OnBeforeDownload(chromiumWebBrowser As IWebBrowser, browser As IBrowser, downloadItem As DownloadItem, callback As IBeforeDownloadCallback) Implements IDownloadHandler.OnBeforeDownload
If PDFIsDownload(downloadItem) Then
'Probably want to use an MD5 file name here
PDFSavePath = $"{PDFCachePath}{downloadItem.SuggestedFileName}"
PDFCacheUrl = $"pdfjs://viewer/cache/{downloadItem.SuggestedFileName}"
callback.Continue(PDFSavePath, False)
End If
End Sub
Private Sub OnDownloadUpdated(chromiumWebBrowser As IWebBrowser, browser As IBrowser, downloadItem As DownloadItem, callback As IDownloadItemCallback) Implements IDownloadHandler.OnDownloadUpdated
If PDFIsDownload(downloadItem) Then
If downloadItem.IsComplete Then
chromiumWebBrowser.LoadUrl($"pdfjs://viewer/web/viewer.html?file={PDFCacheUrl}&url={downloadItem.Url}")
End If
End If
End Sub
' Is the download a PDF?
Private Function PDFIsDownload(Item As DownloadItem) As Boolean
Return PDFEnabled And Item.MimeType = "application/pdf" And Not Item.Url.StartsWith("blob")
End Function
You can provide the original PDF url, derived from the query of the custom scheme url. e.g.
Readonly Property Address() As String
Get
Return If(Browser.Address.StartsWith("pdfjs"), Browser.Address.split("=").Last, Browser.Address)
End Get
End Property
- Handle IsCancelled and IsValid properties in DownloadItem
- Keep reference to callback handler to cancel download externally
- Implement stop and reload with IgnoreCache commands