从 Windows 8 应用程序打印 PDF 文档
Posted
技术标签:
【中文标题】从 Windows 8 应用程序打印 PDF 文档【英文标题】:Printing PDF documents from Windows 8 App 【发布时间】:2013-07-06 04:44:09 【问题描述】:我正在尝试将 PDF 文件从我的 Windows 8 应用程序打印到连接的打印机。我正在使用 WinJS 进行编码,并且知道我必须创建一个打印任务才能从 Windows 8 应用程序启动打印。因此,在查看文档后,我有以下代码:
onPrintTaskRequested: function (e)
var self = Application.navigator.pageControl,
printTask = e.request.createPrintTask("Print Test Doc", function (args)
args.setSource(MSApp.gethtmlPrintDocumentSource(document));
// Register the handler for print task completion event
printTask.oncompleted = self.onPrintTaskCompleted;
);
According to the documentation, the MSApp.getHhtmlPrintDocumentSource method 接受一组特定的数据类型。如文档中所述:
这可以是根文档、IFrame 中的文档、文档 片段或 SVG 文档。请注意 htmlDoc 必须是文档, 不是元素。
显然我不能简单地将 getHtmlPrintDocumentSource 的参数设置为 .PDF 或 .PNG 二进制文件。所以,我很好奇:WinJS 库是否提供了一种打印方法,以便我可以将 PDF 文件打印到连接的打印机?任何人都可以提供一些实施技巧吗?
【问题讨论】:
【参考方案1】:经过反复试验,我终于能够实现从 Windows 8 应用程序打印表示 PDF 二进制文件的 Base64 流。
我正在用 HTML / CSS / WinJS 编写应用程序。基本上这里是对它是如何完成的简要说明:
在default.html
文件中创建一个新的<canvas>
元素。将它放在元素的 open 标记之后。像这样:
<body role="application" class="app">
<canvas id="pdf-render-output"></canvas>
.
.
.
</body>
然后在default.css
文件中,设置一些规则以及打印媒体查询。像这样:
body > canvas
display: none;
.
. /* all your app's default css styles */
.
@media print
body > *
display:none;
max-width: 100%;
html
max-width: 100%;
border-top-color: none;
border-top: 0;
body > canvas
display: block;
border: none;
max-width: 100%;
width: 100%;
height: 100%;
position: relative;
值得注意的是在 CSS 中声明规则的顺序。在声明默认 CSS 规则之后放置打印媒体查询很重要。
设置完成后,javascript 会处理其余部分。基本思想是将 PDF.js 输出渲染到 DOM 中的“隐藏”画布。当文档对象被发送到打印时,将查询 CSS 打印媒体声明,以便隐藏 <body>
下的所有元素,除了 canvas 元素。这是仅打印 PDF 第一页的 javascript:
//Define a container for the Base64 data we'll use with PDF.js
var pdfPrintData = ;
//Function to render PDF to canvas and begin printing contract with Windows 8 OS
printPrescription: function ()
var self = Application.navigator.pageControl,
printManager = Windows.Graphics.Printing.PrintManager.getForCurrentView();
self.getPDF().done(function ()
var pdfStream = pdfPrintData.base64,
pdfFile = convertDataURIToBinary(pdfStream);
PDFJS.disableWorker = true;
PDFJS.getDocument(pdfFile).then(function (pdf)
var numPages = pdf.numPages,
renderCanvas = $('#pdf-render-output')[0];
//setup canvas
renderCanvas.height = pdf.getPage(1).data.getViewport(1).height;
renderCanvas.width = pdf.getPage(1).data.getViewport(1).width;
//Setup a render context for pdf.js to out a pdf file to the canvas.
var renderContext =
canvasContext: renderCanvas.getContext('2d'),
viewport: pdf.getPage(1).data.getViewport(1)
;
//Bring up Windows 8 OS print after PDF is rendered to render context.
pdf.getPage(1).data.render(renderContext).then(function ()
printManager.onprinttaskrequested = self.onPrintTaskRequested;
Windows.Graphics.Printing.PrintManager.showPrintUIAsync();
);
)
);
,
onPrintTaskRequested: function (e)
var self = Application.navigator.pageControl,
printTask = e.request.createPrintTask("Print Prescription", function (args)
args.setSource(MSApp.getHtmlPrintDocumentSource(document));
printTask.oncompleted = self.onPrintTaskCompleted;
);
,
onPrintTaskCompleted: function (e)
if (e.completion === Windows.Graphics.Printing.PrintTaskCompletion.failed)
console.log("[ERX] : Failed to print!");
self.getPDF
方法只是一个检索 Base64 数据流的函数,该数据流在全局 pdfPrintData
对象的 .base64
属性上设置。出于某种原因,我无法使用 pdf.js 将 pdf 呈现到动态创建的文档中的动态创建画布上。我必须将 pdf.js 渲染方法的输出渲染到 DOM 中已经存在的画布上。
【讨论】:
【参考方案2】:据我所知,MSApp.getHtmlPrintDocumentSource(document)
旨在用于 HTML 文档对象,仅此而已。
如果您可以使用 Windows 8.1,您可以尝试通过使用 PdfPage.RenderToStreamAsync 将每个页面导出为光栅图像来从 PDF 文件中组合一个新的 HTML 文档。有一个sample project in MSDN 用于使用此新 API 的 PDF 查看器,您可以在其中学习如何使用此方法。
如果您不能假设 Windows 8.1 并且您需要支持普通的 Windows 8 或 Windows RT (ARM),您可能需要使用第三方库来创建光栅图像或一起进行打印。
Amyuni PDF Creator for WinRT 例如can do the printing for you。 免责声明:我目前在开发库的公司工作
【讨论】:
感谢您的提示。我在谷歌搜索中找到了 Amyuni PDF Creator。是否有使用该软件的免费试用版?此外,您提到“您可能需要使用第三方库来创建光栅图像”。你的意思是像 PDF.js 这样的东西吗? @ariestav 提供 30 天免费试用和免费支持。关于“第三方库”我的意思是您将无法单独使用 WinRT API 进行打印,所以我实际上是指任何第三方库,无论是商业的还是开源的。当我在 SO 中回答问题时,我会尽力做到公平。 关于PDF.js,我或多或少知道它是做什么的,但我没有用过,所以不知道它是否可以用于打印或光栅化。 Amyuni 为不同的架构有单独的文件。我的构建在 VS2012 的配置管理器中设置为“AnyCPU”。考虑到我的构建过程,我将如何包含它? @yms pdf.js 可能无法正常工作。我之前曾尝试过此方法来渲染 pdf,但遇到了未加载字体的问题。它尝试插入不适用于 winjs 的<script>
标签。如果您尝试使用 pdf.js - 将很高兴分享您在 SO 上的发现。以上是关于从 Windows 8 应用程序打印 PDF 文档的主要内容,如果未能解决你的问题,请参考以下文章