如何在 blazor wasm 中创建供下载的 pdf

How can I create a pdf for download in blazor wasm

在 blazor wasm 中,我想创建一个 pdf 文件并使其可供下载。我测试了 pdfflow,但只能在控制台应用程序中实现 运行。有几种商业解决方案(devexpress、syncfusion),但它们非常昂贵。 接下来,我跨过了博客 post Generate PDF files using an html template and Playwright,这对我来说似乎很有希望。不幸的是,它不包含一个完整的示例,我无法做到 运行。这是我尝试过的: 我将 template.html 添加到 wwwroot 文件夹。

template.html

<!DOCTYPE html>
<html>
<head>
    <link rel="stylesheet" href="invoice.css">
</head>
<body style="padding: 3rem">
    <h1>Invoice</h1>
    Awesome company<br />
</body>
</html>

我添加了一个调用 CreatePdf() 的按钮。我从上面的 link 复制代码并根据我的需要修改它(因为例如没有提供方法 LoadOrder(orderId) )。

Index.razor

@page "/"
@using Scriban
@using System.IO
@using Microsoft.Playwright
@inject HttpClient Http

<button class="btn btn-primary" @onclick="CreatePdf">pdf</button>

@code{ 
private async Task CreatePdf()
{
    //var templateContent = File.ReadAllText("template.html");
    var templateContent = await Http.GetStringAsync("template.html");
    var template = Template.Parse(templateContent);

    //var templateData = new { Invoice = LoadOrder(orderId) };
    //var pageContent = template.Render(templateData);
    var pageContent = "testString";

    //var dataUrl = "data:text/html;base64," + Convert.ToBase64String(Encoding.UTF8.GetBytes(pageContent));
    var dataUrl = "data:text/html;base64," + pageContent;

我添加了以下两行,因为没有声明“浏览器”(Source from playwright)。

// Here, the app crashes.
using var playwright = await Playwright.CreateAsync();
var browser = await playwright.Webkit.LaunchAsync();

await using var context = await browser.NewContextAsync();
var page = await context.NewPageAsync();
await page.GotoAsync(dataUrl, new PageGotoOptions { WaitUntil = WaitUntilState.NetworkIdle });

var output = await page.PdfAsync(new PagePdfOptions
{
    Format = "A4",
    Landscape = false,
});

await File.WriteAllBytesAsync("output.pdf", output);
} }

如何制作上面的代码运行?

您不能从浏览器 (js / wasm) 使用 Playwright。因此,您必须使用其他解决方案。例如,您可以使用 jsPDF。该库在将 html 转换为 pdf 时并不完美,但也许适合您的使用。

index.html 中添加一些脚本引用以使用 jsPDF(如果您愿意,也可以使用 npm 安装它们)

<script src="_framework/blazor.webassembly.js"></script>

<!-- jsPDF references -->
<script src="https://unpkg.com/jspdf@latest/dist/jspdf.umd.min.js"></script>
<script src="https://html2canvas.hertzen.com/dist/html2canvas.js"></script>
<script src="https://cdn.jsdelivr.net/npm/dompurify@2.3.3/dist/purify.min.js"></script>

创建一个包含以下内容的文件wwwroot/HtmlToPdf.js

export function generateAndDownloadPdf(htmlOrElement, filename) {
    const doc = new jspdf.jsPDF({
        orientation: 'p',
        unit: 'pt',
        format: 'a4'
    });

    return new Promise((resolve, reject) => {
        doc.html(htmlOrElement, {
            callback: doc => {
                doc.save(filename);
                resolve();
            }
        });
    });
}

export function generatePdf(htmlOrElement) {
    const doc = new jspdf.jsPDF();
    return new Promise((resolve, reject) => {
        doc.html(htmlOrElement, {
            callback: doc => {
                const output = doc.output("arraybuffer");
                resolve(new Uint8Array(output));
            }
        });
    });
}

然后,您可以使用 Razor 组件中的脚本:

@inject IJSRuntime JSRuntime

<button type="button" @onclick="DownloadPdf">Generate</button>

@code {
    async Task DownloadPdf()
    {
        await using var module = await JSRuntime.InvokeAsync<IJSObjectReference>("import", "./HtmlToPdf.js");

        // Generate and download the PDF
        await module.InvokeVoidAsync("generateAndDownloadPdf", "<h1>sample</h1>", "sample.pdf");

        // Generate the PDF and get its content as byte[] (need .NET 6 to support Uint8Array)
        var bytes = await module.InvokeAsync<byte[]>("generatePdf", "<h1>sample</h1>");
    }
}