Net5使用WkHtmlToPdfDotNet创建PDF

发布时间 2023-11-05 00:18:46作者: peng_boke

前言

最近遇到了创建PDF的需求,虽然最后没有采用这个方案,但是基本实现了,记录一下。

1.WkHtmlToPdfDotNet

WkHtmlToPdfDotNet是基于本地 wkhtmltopdf封装的.NET Core类库,主要通过webkit引擎实现html页面转换为pdf文件。并且支持在Windows、Docker、Linux、MacOSX运行。

主要功能实现在线URL转pdf文件或者html代码直接转换为pdf文件,并对css样式、图片等很好的支持,导出的pdf文件和网站相差不大。

2.Nuget

感觉支持挺多的

image-20230909180248589

创建命令

.NET CLI:
dotnet add package Haukcode.WkHtmlToPdfDotNet --version 1.5.86

Packag Manafer:
PM> NuGet\Install-Package Haukcode.WkHtmlToPdfDotNet -Version 1.5.86

github地址:

https://github.com/HakanL/WkHtmlToPdf-DotNet

3.基于HTML生成PDF

这里使用控制台程序生成PDF

在单线程应用程序中使用此转换器:var converter = new BasicConverter(new PdfTools());

static void Main(string[] args)
{
    var converter = new BasicConverter(new PdfTools());
    //var converter = new SynchronizedConverter(new PdfTools());
    var doc = new HtmlToPdfDocument()
    {
        GlobalSettings = {
            ColorMode = ColorMode.Color,
            Orientation = Orientation.Landscape,
            PaperSize = PaperKind.A4,
        },
        Objects = {
                  new ObjectSettings() {
                               PagesCount = true,
                               HtmlContent =gethtmlstr(),
                               WebSettings = {DefaultEncoding = "utf-8" },
                               HeaderSettings = {FontSize = 9, Right = "Page [page] of [toPage]", Line = false  },
                               FooterSettings = {FontSize = 9, Right = "Page [page] of [toPage]" }
                  }
        }
    };
    // 转换为二进制
    byte[] pdf = converter.Convert(doc);
    string dire = System.AppDomain.CurrentDomain.BaseDirectory + "Files";
    // 判断目录是否存在,不存在则创建
    if (!Directory.Exists(dire))
    {
        Directory.CreateDirectory(dire);
    }
    // 文件保存
    using (var stream = new FileStream(Path.Combine(dire, "测试" + DateTime.UtcNow.Ticks.ToString() + ".pdf"), FileMode.Create))
    {
        stream.Write(pdf, 0, pdf.Length);
    }
}


static string gethtmlstr()
{
    return "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n  <head>\r\n    <meta charset=\"UTF-8\" />\r\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\" />\r\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\r\n    <title>Document</title>\r\n  </head>\r\n  <style></style>\r\n  <body> 测试PDF </body>\r\n</html>\r\n";
}

4.API接口

在多线程应用程序和web服务器中使用此转换器。 转换任务保存为阻塞收集,并在单个线程上执行 :var converter = new SynchronizedConverter(new PdfTools());

ServiceCollection注入:

services.AddSingleton(typeof(IConverter), new SynchronizedConverter(new PdfTools()));

实现:

    public class WkHtmlToPdfProvider
    {
        public async Task<byte[]> CreatePdfByHtml(string htmlstr)
        {
            var converter = new SynchronizedConverter(new PdfTools());
            var doc = new HtmlToPdfDocument()
            {
                GlobalSettings = {
                    ColorMode = ColorMode.Color,
                    Orientation = Orientation.Landscape,
                    PaperSize = PaperKind.A4,
                },
                Objects = {
                          new ObjectSettings() {
                                       PagesCount = true,
                                       HtmlContent =htmlstr,
                                       WebSettings = {DefaultEncoding = "utf-8" },
                                       HeaderSettings = {FontSize = 9, Right = "Page [page] of [toPage]", Line = false  },
                                       FooterSettings = {FontSize = 9, Right = "Page [page] of [toPage]" }
                          }
                }
            };
            // 转换为二进制
            byte[] pdf = converter.Convert(doc);
            return await Task.FromResult<byte[]>(pdf);
        }
    }

传入html字符就可以了

AllowAnonymous设置接口不要权限访问,要不前端a标签访问还需要token

Controller:

[HttpGet]
[Route("xxx/CreatePdf/{key}")]
[AllowAnonymous]
public async Task<FileResult> CreatePdf([FromServices] WkHtmlToPdfProvider provider)
{
    var htmlstr = await xxxxx();//生成html
    var bytes = await provider.CreatePdfByHtml(htmlstr);
    return File(bytes, "application/octet-stream", "客户在线对账.pdf");
}

前端:创建a标签下载


    downloadfile() {
        // pdf
        let date = new Date();
        //const fileName = '测试.pdf';
        const link = document.createElement('a'); // 创建a标签
        //link.download = fileName; // a标签添加属性
        link.style.display = 'none';
        link.href =`http://localhost:9008/api/xxx/xxx/CreatePdf/${this.data.id}`;
        document.body.appendChild(link);
        link.click(); // 执行下载
        URL.revokeObjectURL(link.href); // 释放url
        document.body.removeChild(link); // 释放标签
    }

5.Docker部署

如果你用的是微软提供的netcore的linux版本的docker容器,你将需要安装一些库。

下面的例子是基于debian的linux发行版;

在WORKDIR /app命令之前插入以下行 :

RUN apt update
RUN apt install -y libgdiplus
RUN ln -s /usr/lib/libgdiplus.so /lib/x86_64-linux-gnu/libgdiplus.so
RUN apt-get install -y --no-install-recommends zlib1g fontconfig libfreetype6 libx11-6 libxext6 libxrender1 wget gdebi
RUN wget https://github.com/wkhtmltopdf/wkhtmltopdf/releases/download/0.12.5/wkhtmltox_0.12.5-1.stretch_amd64.deb
RUN gdebi --n wkhtmltox_0.12.5-1.stretch_amd64.deb
RUN apt install libssl1.1
RUN ln -s /usr/local/lib/libwkhtmltox.so /usr/lib/libwkhtmltox.so

image-20230909181742859

创作不易,如果感觉帮助到你了,还请多多支持,我会继续努力。

image-20230909182056718