欧美成人精品手机在线观看_69视频国产_动漫精品第一页_日韩中文字幕网 - 日本欧美一区二区

LOGO OA教程 ERP教程 模切知識(shí)交流 PMS教程 CRM教程 開發(fā)文檔 其他文檔  
 
網(wǎng)站管理員

.NET下免費(fèi)開源的PDF類庫(kù)(PDFSharp)

freeflydom
2024年5月25日 11:28 本文熱度 1169

前言

目前.NET 體系下常見的PDF類庫(kù)有AsposeQuestPDFSpireiTextSharp等,有一說(shuō)一都挺好用的,我個(gè)人特別喜歡QuestPDF它基于 C# Fluent API 提供全面的布局引擎;但是這些庫(kù)要么屬于商業(yè)庫(kù)價(jià)格不菲(能理解收費(fèi)),但是年費(fèi)太貴了。要么是有條件限制開源的,如Spire開源版本有各種限制。iTextSharp雖然沒有限制,但是開源協(xié)議不友好(AGPL),用于閉源商業(yè)軟件屬于要掛恥辱柱的行為了。

無(wú)意間發(fā)現(xiàn)了另一款基于.NET6的跨平臺(tái)、免費(fèi)開源(MIT協(xié)議)pdf處理庫(kù):PDFSharp,該庫(kù)還有基于.NET Framework的版本https://pdfsharp.net/ ,.NET6版本好像是去年剛發(fā)布的,還有一個(gè)較為活躍的社區(qū)https://forum.pdfsharp.net/。

嘗試使用了下,還不錯(cuò),該有的都有,簡(jiǎn)單的pdf文件可以直接使用PDFSharp庫(kù)生成,復(fù)雜點(diǎn)的則提供了MigraDoc來(lái)編輯。我自己的小應(yīng)用都已經(jīng)上生成環(huán)境了,個(gè)人覺得該庫(kù)是挺ok的了。

.NET Framework文檔站點(diǎn)下有很多例子大家可以看看:

  

我的使用方式較為粗暴,使用MigraDoc編輯文檔表格,再生成PDF文件。有時(shí)間再嘗試封裝個(gè)類似于QuestPDF的擴(kuò)展庫(kù),太喜歡Fluent這種形式了。

代碼例子

讓我們來(lái)制作下圖的pdf吧

 

新建一個(gè)項(xiàng)目,通過(guò)Nuget引入PDFsharp、PDFsharp-MigraDoc,
若用System.Drawing圖形庫(kù)則不用引用SkiaSharp,我的例子使用SkiaSharp圖形庫(kù)便于跨平臺(tái)。

首先是字體的導(dǎo)入

  • 因?yàn)镻DFSharp本身不支持中文字體,但提供了自定義解析器的處理,所以我們先實(shí)現(xiàn)下中文字體解析器。先將黑體作為嵌入資源導(dǎo)入項(xiàng)目中,路徑是/Fonts/下

  • 新建一個(gè)文件ChineseFontResolver.cs用來(lái)實(shí)現(xiàn)我們的中文解析器

using PdfSharp.Fonts; 

using System.Reflection; 


namespace pdfsharpDemo;

/// <summary>

/// 中文字體解析器

/// </summary>

public class ChineseFontResolver : IFontResolver

{

    /// <summary>

    /// 字體作為嵌入資源所在程序集

    /// </summary>

    public static string FontAssemblyString { get; set; } = "pdfsharpDemo";

    /// <summary>

    /// 字體作為嵌入資源所在命名空間

    /// </summary>

    public static string FontNamespace { get; set; } = "pdfsharpDemo.Fonts";


    /// <summary>

    /// 字體名稱

    /// </summary>

    public static class FamilyNames

    {

        // This implementation considers each font face as its own family.

        /// <summary>

        /// 仿宋

        /// </summary>

        public const string SIMFANG = "simfang.ttf";

        /// <summary>

        /// 黑體

        /// </summary>

        public const string SIMHEI = "simhei.ttf";

        /// <summary>

        /// 楷書

        /// </summary>

        public const string SIMKAI = "simkai.ttf";

        /// <summary>

        /// 隸書

        /// </summary>

        public const string SIMLI = "simli.ttf";

        /// <summary>

        /// 宋體

        /// </summary>

        public const string SIMSUN = "simsun.ttf";

        /// <summary>

        /// 宋體加粗

        /// </summary>

        public const string SIMSUNB = "simsunb.ttf";

        /// <summary>

        /// 幼圓

        /// </summary>

        public const string SIMYOU = "simyou.ttf";

    }



    /// <summary>

    /// Selects a physical font face based on the specified information

    /// of a required typeface.

    /// </summary>

    /// <param name="familyName">Name of the font family.</param>

    /// <param name="isBold">Set to <c>true</c> when a bold font face

    ///  is required.</param>

    /// <param name="isItalic">Set to <c>true</c> when an italic font face 

    /// is required.</param>

    /// <returns>

    /// Information about the physical font, or null if the request cannot be satisfied.

    /// </returns>

    public FontResolverInfo? ResolveTypeface(string familyName, bool isBold, bool isItalic)

    {

        // Note: PDFsharp calls ResolveTypeface only once for each unique combination

        // of familyName, isBold, and isItalic. 


        return new FontResolverInfo(familyName, isBold, isItalic);

        // Return null means that the typeface cannot be resolved and PDFsharp forwards

        // the typeface request depending on PDFsharp build flavor and operating system.

        // Alternatively forward call to PlatformFontResolver.

        //return PlatformFontResolver.ResolveTypeface(familyName, isBold, isItalic);

    }


    /// <summary>

    /// Gets the bytes of a physical font face with specified face name.

    /// </summary>

    /// <param name="faceName">A face name previously retrieved by ResolveTypeface.</param>

    /// <returns>

    /// The bits of the font.

    /// </returns>

    public byte[]? GetFont(string faceName)

    {

        // Note: PDFsharp never calls GetFont twice with the same face name.

        // Note: If a typeface is resolved by the PlatformFontResolver.ResolveTypeface

        //       you never come here.

        var name = $"{FontNamespace}.{faceName}";

        using Stream stream = Assembly.Load(FontAssemblyString).GetManifestResourceStream(name) ?? throw new ArgumentException("No resource named '" + name + "'.");

        int num = (int)stream.Length;

        byte[] array = new byte[num];

        stream.Read(array, 0, num);

        // Return the bytes of a font.

        return array;

    }

}

好了,開始制作我們的pdf吧

// See https://aka.ms/new-console-template for more information

using Microsoft.Extensions.Configuration;

using MigraDoc.DocumentObjectModel;

using MigraDoc.DocumentObjectModel.Tables;

using MigraDoc.Rendering;

using PdfSharp.Drawing;

using PdfSharp.Fonts;

using PdfSharp.Pdf;

using PdfSharp.Pdf.IO;

using pdfsharpDemo;

using SkiaSharp;

using System;

using System.IO;

using static pdfsharpDemo.ChineseFontResolver;


Console.WriteLine("Hello, PDFSharp!");


// 設(shè)置PDFSharp全局字體為自定義解析器

GlobalFontSettings.FontResolver = new ChineseFontResolver();

#region pdf頁(yè)面的基本設(shè)置 

var document = new Document();

var _style = document.Styles["Normal"];//整體樣式

_style.Font.Name = FamilyNames.SIMHEI;

_style.Font.Size = 10;


var _tableStyle = document.Styles.AddStyle("Table", "Normal");//表格樣式

_tableStyle.Font.Name = _style.Font.Name;

_tableStyle.Font.Size = _style.Font.Size;


var _section = document.AddSection();

_section.PageSetup = document.DefaultPageSetup.Clone();

_section.PageSetup.PageFormat = PageFormat.A4; //A4紙規(guī)格

_section.PageSetup.Orientation = Orientation.Landscape;//紙張方向:橫向,默認(rèn)是豎向

_section.PageSetup.TopMargin = 50f;//上邊距 50

_section.PageSetup.LeftMargin = 25f;//左邊距 20

#endregion


//這里采用三個(gè)表格實(shí)現(xiàn)標(biāo)題欄、表格內(nèi)容、底欄提示 

//創(chuàng)建一個(gè)表格,并且設(shè)置邊距

var topTable = _section.AddTable();

topTable.Style = _style.Name;

topTable.TopPadding = 0;

topTable.BottomPadding = 3;

topTable.LeftPadding = 0;


var tableWidth = _section.PageSetup.PageHeight - _section.PageSetup.LeftMargin * 2;

// 標(biāo)題欄分為三格

float[] topTableWidths = [tableWidth / 2, tableWidth / 2];

//生成對(duì)應(yīng)的二列,并設(shè)置寬度

foreach (var item in topTableWidths)

{

    var column = topTable.AddColumn();

    column.Width = item;

}


//生成行,設(shè)置標(biāo)題

var titleRow = topTable.AddRow();

titleRow.Cells[0].MergeRight = 1;//向右跨一列(合并列)

titleRow.Cells[0].Format.Alignment = ParagraphAlignment.Center;//元素居中

var parVlaue = titleRow.Cells[0].AddParagraph();

parVlaue.Format = new ParagraphFormat();

parVlaue.Format.Font.Bold = true;//粗體

parVlaue.Format.Font.Size = 16;//字體大小

parVlaue.AddText("我的第一個(gè)PDFSharp例子");


//生成標(biāo)題行,這里我們?cè)O(shè)置兩行

var row2 = topTable.AddRow();

var noCell = row2.Cells[0];

noCell.Format.Alignment = ParagraphAlignment.Left;

noCell.AddParagraph().AddText($"編號(hào):00000001");

var orgNameCell = row2.Cells[1];

orgNameCell.Format.Alignment = ParagraphAlignment.Right;

orgNameCell.AddParagraph().AddText("單位:PDFSharp研究小組");


var row3 = topTable.AddRow();

var createAtCell = row3.Cells[0];

createAtCell.Format.Alignment = ParagraphAlignment.Left;

createAtCell.AddParagraph().AddText($"查詢時(shí)間:{DateTime.Now.AddDays(-1):yyyy年MM月dd日 HH:mm}");

var printTimeCell = row3.Cells[1];

printTimeCell.Format.Alignment = ParagraphAlignment.Right;

printTimeCell.AddParagraph().AddText($"打印時(shí)間:{DateTime.Now:yyyy年MM月dd日 HH:mm}");


//表格內(nèi)容

var contentTable = _section.AddTable();

contentTable.Style = _style.Name;

contentTable.Borders = new Borders

{

    Color = Colors.Black,

    Width = 0.25

};

contentTable.Borders.Left.Width = 0.5;

contentTable.Borders.Right.Width = 0.5;

contentTable.TopPadding = 6;

contentTable.BottomPadding = 0;


//這里設(shè)置8列好了

var tableWidths = new float[8];

tableWidths[0] = 30;

tableWidths[1] = 60;

tableWidths[2] = 40;

tableWidths[5] = 60;

tableWidths[6] = 80;

float w2 = (_section.PageSetup.PageHeight - (_section.PageSetup.LeftMargin * 2) - tableWidths.Sum()) / 2;//假裝自適應(yīng),哈哈哈

tableWidths[3] = w2;

tableWidths[4] = w2;

//生成列

foreach (var item in tableWidths)

{

    var column = contentTable.AddColumn();

    column.Width = item;

    column.Format.Alignment = ParagraphAlignment.Center;

}


//生成標(biāo)題行 

var headRow = contentTable.AddRow();

headRow.TopPadding = 6;

headRow.BottomPadding = 6;

headRow.Format.Font.Bold = true;

headRow.Format.Font.Size = "12";

headRow.VerticalAlignment = VerticalAlignment.Center;

headRow.Cells[0].AddParagraph().AddText("序號(hào)");

headRow.Cells[1].AddParagraph().AddText("姓名");

headRow.Cells[2].AddParagraph().AddText("性別");

headRow.Cells[3].AddParagraph().AddText("家庭地址");

headRow.Cells[4].AddParagraph().AddText("工作單位");

var cParVlaue = headRow.Cells[5].AddParagraph();

"銀行卡總額(元)".ToList()?.ForEach(o => cParVlaue.AddChar(o));//自動(dòng)換行 使用AddChar

headRow.Cells[6].AddParagraph().AddText("聯(lián)系電話");



//內(nèi)容列,隨便填點(diǎn)吧 用元組實(shí)現(xiàn),懶得搞個(gè)類了

List<(string name, string sex, string addree, string workplace, decimal? amount, string phone)> contentData = new()

{

    new () {name="張珊",sex="女",addree="市政府宿舍",workplace="市政府",amount=12002M,phone="138********3333"},

    new () {name="李思",sex="女",addree="省政府宿舍大樓下的小破店旁邊的垃圾桶前面的別墅",workplace="省教育局",amount=220000M,phone="158********3456"},

    new () {name="王武",sex="男",addree="鳳凰村",workplace="老破小公司",amount=-8765M,phone="199********6543"},

    new () {name="",sex="",addree="",workplace="",amount=null,phone=""},

};

var index = 1;

foreach (var (name, sex, addree, workplace, amount, phone) in contentData)

{

    var dataRow = contentTable.AddRow();

    dataRow.TopPadding = 6;

    dataRow.BottomPadding = 6;

    dataRow.Cells[0].AddParagraph().AddText($"{index++}");

    dataRow.Cells[1].AddParagraph().AddText(name);

    dataRow.Cells[2].AddParagraph().AddText(sex);

    var addreeParVlaue = dataRow.Cells[3].AddParagraph();

    addree?.ToList()?.ForEach(o => addreeParVlaue.AddChar(o));//自動(dòng)換行 使用AddChar

    dataRow.Cells[4].AddParagraph().AddText(workplace);

    dataRow.Cells[5].AddParagraph().AddText(amount?.ToString() ?? "");

    dataRow.Cells[6].AddParagraph().AddText(phone);

}



//空白 段落 分隔下間距

Paragraph paragraph = new();// 設(shè)置段落格式

paragraph.Format.SpaceBefore = "18pt"; // 設(shè)置空行高度為 12 磅 

document.LastSection.Add(paragraph); // 將段落添加到文檔中


//底欄提示 

var tipsTable = _section.AddTable();

tipsTable.Style = _style.Name;

tipsTable.TopPadding = 3;

var tipsTableColumn = tipsTable.AddColumn();

tipsTableColumn.Width = _section.PageSetup.PageHeight - _section.PageSetup.LeftMargin * 2;

var tipsParagraph = tipsTable.AddRow().Cells[0].AddParagraph();

tipsParagraph.Format.Font.Bold = true;

tipsParagraph.Format.Font.Color = Colors.Red; //設(shè)置紅色

tipsParagraph.AddText($"注:隱私信息是我們必須要注重的廢話連篇的東西,切記切記,不可忽視,因小失大;");



#region 頁(yè)碼

_section.PageSetup.DifferentFirstPageHeaderFooter = false;

var pager = _section.Footers.Primary.AddParagraph();

pager.AddText($"第\t");

pager.AddPageField();

pager.AddText($"\t頁(yè)");

pager.Format.Alignment = ParagraphAlignment.Center;

#endregion


//生成PDF

var pdfRenderer = new PdfDocumentRenderer();

using var memoryStream = new MemoryStream();

pdfRenderer.Document = document;

pdfRenderer.RenderDocument();

pdfRenderer.PdfDocument.Save(memoryStream);

var pdfDocument = PdfReader.Open(memoryStream);


//為了跨平臺(tái) 用的是SkiaSharp,大家自己轉(zhuǎn)為System.Drawing實(shí)現(xiàn)即可,較為簡(jiǎn)單就不寫了

#region 水印

using var watermarkMemoryStream = new MemoryStream();

var watermarkImgPath = "D:\\logo.png";

using var watermarkFile = System.IO.File.OpenRead(watermarkImgPath);// 讀取文件 

using var fileStream = new SKManagedStream(watermarkFile);

using var bitmap = SKBitmap.Decode(fileStream);

//設(shè)置半透明

var transparent = new SKColor(0, 0, 0, 0);

for (int w = 0; w < bitmap.Width; w++)

{

    for (int h = 0; h < bitmap.Height; h++)

    {

        SKColor c = bitmap.GetPixel(w, h);

        SKColor newC = c.Equals(transparent) ? c : new SKColor(c.Red, c.Green, c.Blue, 70);

        bitmap.SetPixel(w, h, newC);

    }

}

using var resized = bitmap.Resize(new SKImageInfo(200, 80), SKFilterQuality.High);

using var newImage = SKImage.FromBitmap(resized);

newImage.Encode(SKEncodedImageFormat.Png, 90).SaveTo(watermarkMemoryStream); // 保存文件 

using var image = XImage.FromStream(watermarkMemoryStream);

var xPoints = 6;

var yPoints = 4;

for (int i = 0; i <= xPoints; i++)

{

    var xPoint = image.PointWidth * i * 1.2;

    var xTranslateTransform = xPoint + image.PointWidth / 2;

    for (int j = 0; j <= yPoints; j++)

    {

        var yPoint = image.PointHeight * j * 1.2;

        var yTranslateTransform = yPoint + image.PointHeight / 8;

        foreach (var page in pdfDocument.Pages)

        {

            using var xgr = XGraphics.FromPdfPage(page, XGraphicsPdfPageOptions.Prepend);

            xgr.TranslateTransform(xTranslateTransform, yTranslateTransform);

            xgr.RotateTransform(-45);

            xgr.TranslateTransform(-xTranslateTransform, -yTranslateTransform);

            xgr.DrawImage(image, xPoint, yPoint, 200, 80);

        }

    }

}

#endregion


pdfDocument.Save(memoryStream);

var outputPdfFilePath = "D:\\pdfdemo.pdf";

//保存到本地

using var fs = new FileStream(outputPdfFilePath, FileMode.Create);

byte[] bytes = new byte[memoryStream.Length];

memoryStream.Seek(0, SeekOrigin.Begin);

memoryStream.Read(bytes, 0, (int)memoryStream.Length);

fs.Write(bytes, 0, bytes.Length);



Console.WriteLine("生成成功!");


至此我們就制作好了一個(gè)簡(jiǎn)單的pdf,當(dāng)然了這里沒有加上文件信息那些,僅僅是生成內(nèi)容罷了,有那些需要的可以自己根據(jù)文檔站點(diǎn)看看如何設(shè)置。

上述代碼的源碼地址:https://gitee.com/huangguishen/MyFile/tree/master/PDFSharpDemo



該文章在 2024/5/25 11:28:24 編輯過(guò)
關(guān)鍵字查詢
相關(guān)文章
正在查詢...
點(diǎn)晴ERP是一款針對(duì)中小制造業(yè)的專業(yè)生產(chǎn)管理軟件系統(tǒng),系統(tǒng)成熟度和易用性得到了國(guó)內(nèi)大量中小企業(yè)的青睞。
點(diǎn)晴PMS碼頭管理系統(tǒng)主要針對(duì)港口碼頭集裝箱與散貨日常運(yùn)作、調(diào)度、堆場(chǎng)、車隊(duì)、財(cái)務(wù)費(fèi)用、相關(guān)報(bào)表等業(yè)務(wù)管理,結(jié)合碼頭的業(yè)務(wù)特點(diǎn),圍繞調(diào)度、堆場(chǎng)作業(yè)而開發(fā)的。集技術(shù)的先進(jìn)性、管理的有效性于一體,是物流碼頭及其他港口類企業(yè)的高效ERP管理信息系統(tǒng)。
點(diǎn)晴WMS倉(cāng)儲(chǔ)管理系統(tǒng)提供了貨物產(chǎn)品管理,銷售管理,采購(gòu)管理,倉(cāng)儲(chǔ)管理,倉(cāng)庫(kù)管理,保質(zhì)期管理,貨位管理,庫(kù)位管理,生產(chǎn)管理,WMS管理系統(tǒng),標(biāo)簽打印,條形碼,二維碼管理,批號(hào)管理軟件。
點(diǎn)晴免費(fèi)OA是一款軟件和通用服務(wù)都免費(fèi),不限功能、不限時(shí)間、不限用戶的免費(fèi)OA協(xié)同辦公管理系統(tǒng)。
Copyright 2010-2025 ClickSun All Rights Reserved