SkiaSharp跨平台绘图研究4-在PDF上绘图

SkiaSharp跨平台绘图研究4-PDF上绘图

在很多应用场景中,软件系统是要有打印报告功能的,要知道SkiaSharp还能够在PDF上绘图,都不知道该怎么夸它了,一套绘图代码,可以在PC端,移动端,Linux云服务器到处用,还能导出PDF,打印到A4纸,这跨平台能力也太强大了。

 

继续沿用之前的Asp.Net Core项目,在网页上增加一个导出PDF报告的功能,然后创建一个PDF文件,可以下载,也可以直接打印。

 

PDF上绘图

PDF上绘图的代码跟WPF项目基本一样。

 

using SkiaSharp;

namespace WebMvcDemo
{
    /// <summary>
    /// 创建PDF绘图文件
    /// </summary>
    public class SkiaPdfMaker
    {
        /// <summary>
        /// 每毫米对应多少打印点数 = 每英寸打印多少点数 / 每英寸多少毫米 = 2.83464567
        /// Dpi打印分辨率,Dot Per Inch,每英寸打印点数,默认72
        /// 1英寸=25.4毫米
        /// </summary>
        public const float DotPermm = SKDocument.DefaultRasterDpi / 25.4f;

        /// <summary>
        /// 导出PDF文件
        /// </summary>
        /// <returns></returns>
        public byte[] ExportToPdf()
        {
            Console.WriteLine($"{DateTime.Now}, 开始导出PDF");

            using MemoryStream stream = new MemoryStream();

            var pdfMetadata = new SKDocumentPdfMetadata
            {
                Author = "SkiaPdfMaker",
            };

            //初始化一个PdfDocument类实例
            using SKDocument pdfDocument = SKDocument.CreatePdf(stream, pdfMetadata);

            //新添加一页纸张,创建纸张大小的画布,A4尺寸 = 210 X 297 mm
            float paperWidth = DotPermm * 210;
            float paperHeight = DotPermm * 297;
            var canvas = pdfDocument.BeginPage(paperWidth, paperHeight);

            using var paint = new SKPaint
            {
                Color = SKColors.Black,
                IsAntialias = true,
                Typeface = SkiaChinaFont.ChinaFont,
                TextSize = 24
            };

            string msg = $"{DateTimeOffset.Now:T}, 还有1万行Skia绘图代码...";
            canvas.DrawText(msg, 0, 30, paint);

            using var linePaint = new SKPaint()
            {
                Color = (DateTimeOffset.Now.Second % 4 <= 1) ? SKColors.Red : SKColors.Green,
                Style = SKPaintStyle.Stroke,//不填充
                StrokeWidth = 3,
            };
            canvas.DrawRect(10, 50, paperWidth - 20, paperHeight - 60, linePaint);

            msg += $", linePaint.Color={linePaint.Color}, skContainer.CanvasSize={paperWidth} x {paperHeight}";
            Console.WriteLine(msg);

            //结束一页内容
            pdfDocument.EndPage();

            //结束文档内容
            pdfDocument.Close();

            byte[] ary = stream.ToArray();

            return ary;
        }
    }
}

 

 

在页面下载PDF

 

控制器Action就是返回一个PDF文件类型

 

        /// <summary>
        /// 导出Skia绘图PDF文件
        /// </summary>
        /// <returns></returns>
        public IActionResult ExportSkiaPdf()
        {
            //导出PDF文件
            var skiaPdfMaker = new SkiaPdfMaker();

            var ary = skiaPdfMaker.ExportToPdf();

            string httpHeader = $"attachment; filename={DateTime.Now:yyyyMMdd-HHmmss}.pdf";
            HttpContext.Response.Headers.Add("content-disposition", httpHeader);

            return File(ary, "application/pdf");
        }

 

主页增加一个超级链接按钮

    <a class="btn btn-info m-1" href="/Home/ExportSkiaPdf" target="_blank">导出PDF</a>

运行网站,在浏览器中点击【导出PDF】超级链接,就会下载创建的PDF文件。

 

 

发布到腾讯云CentOS操作系统容器里运行也一样的结果。

 

该方案存在的问题

这个如此简单的PDF文件居然有1.7M字节,我不知道该说什么好了。为什么会这样,我也不知道。我曾经对比过其他PDF生成方案创建的PDF文件,比SkiaSharp小多了!SkiaSharp生成的PDF如果不使用中文字库,仍然有500k字节,貌似SkiaSharp把整个中文字库全部嵌入到PDF里边去了。

 

使用老牌iTextSharp创建PDF方案做个对比,NuGet安装iTextSharp.LGPLv2.Core,这个是iText免费版的绝版。

    <PackageReference Include="iTextSharp.LGPLv2.Core" Version="1.7.5" />

 

使用iTextSharp创建同样的PDF文件,iText的坐标系是倒置的,绘图代码跟SkiaSharp不能共用。

 

using iTextSharp.text;
using iTextSharp.text.pdf;

namespace WebMvcDemo
{
    /// <summary>
    /// 创建PDF绘图文件
    /// </summary>
    public class ItextPdfMaker
    {
        /// <summary>
        /// 导出PDF文件
        /// </summary>
        /// <returns></returns>
        public byte[] ExportToPdf()
        {
            Console.WriteLine($"{DateTime.Now}, iText开始导出PDF");

            using MemoryStream stream = new MemoryStream();

            //初始化一个Document类实例,创建纸张大小的画布,A4尺寸 = 210 X 297 mm,= 595 x 842,设置页边距全0,整个页面全部作为画布
            var document = new Document(PageSize.A4, 0, 0, 0, 0);

            //必须先获取PdfWriter,然后document.Open,如果交换顺序,报错Document not open
            PdfWriter writer = PdfWriter.GetInstance(document, stream);

            document.AddAuthor("ItextPdfMaker");
            document.AddCreator("ItextPdfMaker");

            document.Open();

            var canvas = writer.DirectContent;

            var textfont = new Font(ItextChinaFont.ChinaFont)
            {
                Color = BaseColor.Black,
                Size = 24
            };

            string msg = $"{DateTimeOffset.Now:T}, 还有1万行iText绘图代码...";
            ColumnText.ShowTextAligned(canvas, Element.ALIGN_LEFT, new Phrase(msg, textfont), 0, canvas.PdfDocument.Top - 30, 0);

            var lineColor = (DateTimeOffset.Now.Second % 4 <= 1) ? BaseColor.Red : BaseColor.Green;

            canvas.SetColorStroke(lineColor);

            canvas.SetLineWidth(3);

            //左边-底部-右边-顶部
            canvas.Rectangle(10, canvas.PdfDocument.Top - (PageSize.A4.Height - 60), PageSize.A4.Width - 20, canvas.PdfDocument.Top - 120);

            canvas.Stroke();

            msg += $", lineColor={lineColor.ToArgb():X2}, CanvasSize={PageSize.A4}";
            Console.WriteLine(msg);

            //结束一页内容
            //document.NewPage();

            //结束文档内容
            document.Close();

            byte[] ary = stream.ToArray();

            return ary;
        }
    }
}

 

创建中文字体类

using iTextSharp.text.pdf;

namespace WebMvcDemo
{
    /// <summary>
    /// iText中文字体
    /// </summary>
    public static class ItextChinaFont
    {
        public static BaseFont ChinaFont { get; private set; }

        static ItextChinaFont()
        {
            //加载字体资源文件方案,需要把字体文件复制运行目录下,设置文件属性为如果较新则复制
            string fontPath = Path.Combine(AppContext.BaseDirectory, "DroidSansFallback.ttf");
            ChinaFont = BaseFont.CreateFont(fontPath, BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
        }
    }
}

iTextSharp创建的PDF40k字节,部署到腾讯云CentOS容器也没有什么依赖库。所以最终我没有把SkiaSharp方案用于产品中,仍然使用了老掉牙的iTextSharp免费版本,真是非常遗憾。希望将来能找到问题原因,重新把SkiaSharp创建PDF用起来。

 

DEMO源代码参见:https://gitee.com/woodsun/skia-sharp-demo

 

posted on 2021-11-17 23:05  SunnyTrudeau  阅读(1107)  评论(0编辑  收藏  举报