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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM