问题描述
您好,我正在使用 Android 和 UWP 平台参与一个 Xamarin PCL 项目.作为一项功能,用户应该能够打开 pdf 文件.
为此,我使用 Mozilla pdf.js.我已按照此链接在 Android 和 UWP 上完成此操作.https://developer.xamarin.com/recipes/cross-platform/xamarin-forms/controls/display-pdf/仅适用于 UWP,我无法使其正常运行.
这是我的 UWP 自定义渲染器
[程序集:ExportRenderer(typeof(PdfView),typeof(PDF.UWP.Renderers.PdfViewRenderer))]命名空间 PDF.UWP.Renderers{//////UWP app的asset文件夹必须包含pdfjs文件夹和文件.///</总结>公共类 PdfViewRenderer:WebViewRenderer{protected override void OnElementChanged(ElementChangedEventArgs e){base.OnElementChanged(e);if (e.NewElement != null){PdfView pdfView = 元素作为 PdfView;string sFile = string.Format("ms-appx-web://{0}", WebUtility.UrlEncode(pdfView.Uri));Control.Source = new Uri(string.Format("ms-appx-web:///Assets/pdfjs/web/viewer.html?file={0}", sFile));}}}}
这是我的 PdfView 类.
公共类PdfView:WebView{公共静态只读 BindableProperty DocumentInfoProperty =BindableProperty.Create(propertyName: nameof(TheDocumentInfo), returnType: typeof(DocumentInfo),declaringType: typeof(PdfView), defaultValue: default(DocumentInfo));公共文档信息 TheDocumentInfo{获取{返回(文档信息)GetValue(文档信息属性);}设置 { SetValue(DocumentInfoProperty, value);}}公共字符串 Uri { get { return TheDocumentInfo.LocalUrl;} }public string FileName { get { return TheDocumentInfo.FileName;} }}
uwp 上的文件位置 ="ms-appx-web://C%3A%5CUsers%5CUser%5CAppData%5CLocal%5CPackages%5CPDFTEST.UWP_v4j5n0js0cwst%5CLocalState%5CPDFTest.pdf"
这是正确的.
但错误是:
消息:检索 PDF 时出现意外的服务器响应 (0)ms-appx-web://C:/Users/User/AppData/Local/Packages/PDFTest.UWP_v4j5n0js0cwst/LocalState/PDFTest.pdf/".
更新
我重新创建了渲染器:
protected override void OnElementChanged(ElementChangedEventArgs e){base.OnElementChanged(e);if (e.NewElement != null){//TODO: 测试PdfView pdfView = 元素作为 PdfView;string sFile = string.Format("ms-appx-web://{0}/{1}", pdfView.Uri.Replace(pdfView.FileName, ""), WebUtility.UrlEncode(pdfView.FileName));Control.Source = new Uri(string.Format("ms-appx-web:///Assets/pdfjs/web/viewer.html?file={0}", sFile));}}
我不知道这是否是我问题的解决方案,但此错误已消失.现在的错误是:
PDF.js v1.1.366(版本:9e9df56)
消息:流必须有数据
更新(我不知道你是否应该在这个问题中添加这个,或者我是否应该再做一个).
我的错误依旧
流必须有数据
我现在知道为什么了.因为我正在开发一个 UWP 应用程序并且我想访问我的安装文件夹之外的文件.这个位置是
C:UsersUserAppDataLocalPackagesPDFTest.UWP_v4j5n0js0cwstLocalState
显然我无法访问安装文件夹外的文件.这包括将文件复制到我的安装文件夹并在那里阅读.
更新我的项目中有 2 个版本的 pdf.js.(1.1.366 和 1.9.426)这是我现在的代码
protected override void OnElementChanged(ElementChangedEventArgs e){base.OnElementChanged(e);if (e.NewElement != null){PdfView pdfView = 元素作为 PdfView;var uriString = "ms-appdata:///local/" + WebUtility.UrlEncode(pdfView.FileName);Control.Source = new Uri(string.Format("ms-appx-web:///Assets/pdfjs/web/viewer.html?file={0}", uriString));}}
当我尝试使用 Launcher.LaunchFileAsync 打开文件并使用 uriString 时,它会打开我的浏览器并显示文件.
在我的应用程序中,我收到以下错误
(v1.1.366) 流必须有数据.
(v1.9.426) 检索 PDFms-appdata:///local/PDFTest.pdf"时出现意外的服务器响应 (0).
我知道 pdf uri 是正确且可访问的,但它仍然不起作用.(对于 v1.9.426,我在 viewer.js 中添加了
var HOSTED_VIEWER_ORIGINS = ['null', 'http://mozilla.github.io', 'https://mozilla.github.io'、'ms-appdata://'、'ms-appx-web://PDFTest.uwp'];)
您已使用 ms-appx-web:
uri 方案作为您的 pdf 文件访问路径.实际上,您的 pdf 路径是存储在应用程序本地文件夹中的 C:UsersUserAppDataLocalPackagesPDFTest.UWP_v4j5n0js0cwstLocalState
.所以文件不会被访问.
我还使用ms-appdata:///local/"uri 方案进行了测试,以访问基于您的项目的 pdf 文件.不幸的是,它不能被 viewer.js
识别.
然后,我尝试将 pdf 文件转换为 Base64String
,然后通过调用 viewer.js
中的 openPdfAsBase64
JS 函数打开它.
private async TaskOpenAndConvert(字符串文件名){var 文件夹 = ApplicationData.Current.LocalFolder;var file = await folder.GetFileAsync(FileName);var filebuffer = await file.OpenAsync(FileAccessMode.Read);var reader = new DataReader(filebuffer.GetInputStreamAt(0));var bytes = new byte[filebuffer.Size];等待 reader.LoadAsync((uint)filebuffer.Size);reader.ReadBytes(bytes);返回 Convert.ToBase64String(bytes);}
使用
protected override void OnElementChanged(ElementChangedEventArgs e){base.OnElementChanged(e);if (e.NewElement != null){Control.Source = new Uri("ms-appx-web:///Assets/pdfjs3/web/viewer.html");Control.LoadCompleted += Control_LoadCompleted;}}private async void Control_LoadCompleted(object sender, Windows.UI.Xaml.Navigation.NavigationEventArgs e){CustomWebView pdfView = Element as CustomWebView;if (string.IsNullOrEmpty(pdfView?.Filename)) 返回;var ret = await OpenAndConvert(pdfView?.Filename);var obj = await Control.InvokeScriptAsync("openPdfAsBase64", new[] { ret });}
你可以使用这个 viewer.js
添加了 openPdfAsBase64
方法.
得到以下提示:如何将 PDFjs 嵌入您的 C# 项目.
Hy, I'm working in a Xamarin PCL project with the platforms Android and UWP. As a feature the user should be able to open an pdf file.
For this I'm using Mozilla pdf.js. I have followed this link to get it done on Android and UWP.https://developer.xamarin.com/recipes/cross-platform/xamarin-forms/controls/display-pdf/Only for UWP I can't get it to function.
Here is my custom renderer for UWP
[assembly: ExportRenderer(typeof(PdfView),
typeof(PDF.UWP.Renderers.PdfViewRenderer))]
namespace PDF.UWP.Renderers
{
/// <summary>
/// The asset folder of the UWP app must contain the pdfjs folder and files.
/// </summary>
public class PdfViewRenderer: WebViewRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<WebView> e)
{
base.OnElementChanged(e);
if (e.NewElement != null)
{
PdfView pdfView = Element as PdfView;
string sFile = string.Format("ms-appx-web://{0}", WebUtility.UrlEncode(pdfView.Uri));
Control.Source = new Uri(string.Format("ms-appx-web:///Assets/pdfjs/web/viewer.html?file={0}", sFile));
}
}
}
}
Here is my PdfView class.
public class PdfView: WebView
{
public static readonly BindableProperty DocumentInfoProperty =
BindableProperty.Create(propertyName: nameof(TheDocumentInfo), returnType: typeof(DocumentInfo),
declaringType: typeof(PdfView), defaultValue: default(DocumentInfo));
public DocumentInfo TheDocumentInfo
{
get { return (DocumentInfo)GetValue(DocumentInfoProperty); }
set { SetValue(DocumentInfoProperty, value); }
}
public string Uri { get { return TheDocumentInfo.LocalUrl; } }
public string FileName { get { return TheDocumentInfo.FileName; } }
}
And this is correct.
But the error is:
UPDATE
I have recreated the renderer to:
protected override void OnElementChanged(ElementChangedEventArgs<WebView> e)
{
base.OnElementChanged(e);
if (e.NewElement != null)
{
// TODO: testen
PdfView pdfView = Element as PdfView;
string sFile = string.Format("ms-appx-web://{0}/{1}", pdfView.Uri.Replace(pdfView.FileName, ""), WebUtility.UrlEncode(pdfView.FileName));
Control.Source = new Uri(string.Format("ms-appx-web:///Assets/pdfjs/web/viewer.html?file={0}", sFile));
}
}
I don't know if this is the solution to my problem but this error is gone.The error now is:
UPDATE (I don't know if u should add this in this question or if I should made another one).
My error is still
I know now why. Because I'm developing a UWP application and I want to access a file outside my instal folder. This location is
Apperently I can't access files outside my instalation folder. This includes coping the file to my install folder and read it there.
UPDATEI have 2 versions of pdf.js in my project. (1.1.366 and 1.9.426)This is my code now
protected override void OnElementChanged(ElementChangedEventArgs<WebView> e)
{
base.OnElementChanged(e);
if (e.NewElement != null)
{
PdfView pdfView = Element as PdfView;
var uriString = "ms-appdata:///local/" + WebUtility.UrlEncode(pdfView.FileName);
Control.Source = new Uri(string.Format("ms-appx-web:///Assets/pdfjs/web/viewer.html?file={0}", uriString));
}
}
When I try to open the file with Launcher.LaunchFileAsync and use the uriString it opens my browser and shows me the file.
In my application I get the following error's
I know that the pdf uri is correct and accessible but it still doesn't work.(for v1.9.426 I have added in viewer.js
You have use ms-appx-web:
uri scheme as your pdf file access path. Actually, your pdf path is C:UsersUserAppDataLocalPackagesPDFTest.UWP_v4j5n0js0cwstLocalState
that stored in the app's local folder. So the file will not be accessed.
I have also tested with "ms-appdata:///local/" uri scheme to access the pdf file base on your project. Unfortunately, It can't be recognised by viewer.js
.
And then, I tried to convert pdf file into Base64String
then opening it by calling the openPdfAsBase64
JS function in the viewer.js
.
private async Task<string> OpenAndConvert(string FileName)
{
var folder = ApplicationData.Current.LocalFolder;
var file = await folder.GetFileAsync(FileName);
var filebuffer = await file.OpenAsync(FileAccessMode.Read);
var reader = new DataReader(filebuffer.GetInputStreamAt(0));
var bytes = new byte[filebuffer.Size];
await reader.LoadAsync((uint)filebuffer.Size);
reader.ReadBytes(bytes);
return Convert.ToBase64String(bytes);
}
Usage
protected override void OnElementChanged(ElementChangedEventArgs<WebView> e)
{
base.OnElementChanged(e);
if (e.NewElement != null)
{
Control.Source = new Uri("ms-appx-web:///Assets/pdfjs3/web/viewer.html");
Control.LoadCompleted += Control_LoadCompleted;
}
}
private async void Control_LoadCompleted(object sender, Windows.UI.Xaml.Navigation.NavigationEventArgs e)
{
CustomWebView pdfView = Element as CustomWebView;
if (string.IsNullOrEmpty(pdfView?.Filename)) return;
var ret = await OpenAndConvert(pdfView?.Filename);
var obj = await Control.InvokeScriptAsync("openPdfAsBase64", new[] { ret });
}
You could use this viewer.js
that was added openPdfAsBase64
method.
Got hints following: How to embed the PDFjs into your C# Project.
这篇关于如何在安装文件夹外的 xamarin pcl uwp 中显示 pdf 文件?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!