NET|C#生成PDF文件

项目需要在线生成PDF文件,我首先考虑采用itextsharp控件来实现。具体方法参考 https://sourceforge.net/projects/itextsharp/

1.首先利用nuget 引入该控件包。
 
image.png
2、然后直接创建就可以了。
using iTextSharp.text;
using iTextSharp.text.pdf;
using System;
using System.Collections.Generic;
using System.Data;
using System.IO;
using System.Linq;
using System.Text;
using System.Web;


public class CreatePDF
{
    private static CreatePDF instance;
    public static CreatePDF GetInstance()
    {
        if (instance == null)
        {
            instance = new CreatePDF();
        }
        return instance;
    }

    private static Document doc;
    //string fontdb = AppDomain.CurrentDomain.BaseDirectory + "Template\\msyh.ttc";

    //private static BaseFont bf = BaseFont.CreateFont(@"C://Windows/Fonts/simsun.ttc,0", BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
    static string fontdb = (AppDomain.CurrentDomain.BaseDirectory + "Template\\msyh.ttf").Replace("\\", "/");
    private static BaseFont bf = BaseFont.CreateFont(fontdb + "", BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
    //四种字体
    private static Font fontBig = new Font(bf, 14, Font.BOLD);

    private static Font fontSmall = new Font(bf, (float)10.5, Font.BOLD);
    private static Font fontSmallNoBold = new Font(bf, (float)10.5);
    private static float IndentationLeft = 50;//距左边距
    //如果要传参数进来,可自定义
    public string GeneratePDF(string name)
    {
        doc = new Document(PageSize.A4);
        string filePath = string.Empty;
        try
        {
            //MemoryStream ms2 = new MemoryStream();
            string fileName = string.Format("{0}.pdf", DateTime.Now.ToString("yyyyMMddHHmmss"));
            filePath = AppDomain.CurrentDomain.BaseDirectory + "Template\\" + fileName;
            FileStream fs = new FileStream(filePath, FileMode.Create);//创建临时文件,到时生成好后删除
            PdfWriter writer = PdfWriter.GetInstance(doc, fs);
            writer.CloseStream = false;//把doc内容写入流中
            doc.Open();

            //核心操作
            CreateLine(name);//生成一条下横线

            #region 添加水印
            string waterMarkName = "机密";

            #endregion

            doc.Close();
            MemoryStream ms = new MemoryStream();
            if (fs != null)
            {
                byte[] bytes = new byte[fs.Length];//定义一个长度为fs长度的字节数组
                fs.Read(bytes, 0, (int)fs.Length);//把fs的内容读到字节数组中
                ms.Write(bytes, 0, bytes.Length);//把字节内容读到流中
                fs.Flush();
                fs.Close();
            }
            MemoryStream waterMS = SetWaterMark(ms, filePath, waterMarkName);//先生成水印,再删除临时文件
            //if (File.Exists(filePath))//判断临时文件是否存在,如果存在则删除
            //{
            //    File.Delete(filePath);
            //    GC.Collect();//回收垃圾
            //}
            //SendFile(fileName, waterMS);//把PDF文件发送回浏览器
        }
        catch (DocumentException ex)
        {
            throw new Exception(ex.Message);
        }
        return filePath;
    }
    #region 生成一条横线
    private static void CreateLine(string name)
    {
        PdfPTable table = new PdfPTable(1);//一个单元格的

        PdfPCell cell = new PdfPCell();
        Image gif = Image.GetInstance(AppDomain.CurrentDomain.BaseDirectory + "Template\\logo.png");
        gif.ScaleAbsoluteWidth(100);
        cell.AddElement(gif);
        cell.BorderWidth = 0f;
        cell.BorderWidthBottom = 0.2f;
        table.AddCell(cell);

        doc.Add(table);
    }
    #endregion


    #region 生成页码
    private static void AddPageNumberContent()
    {
        var content = new Paragraph("共   页  第   页", fontSmall);
        content.IndentationRight = IndentationLeft + 20;
        content.Alignment = 2;    //居左
        doc.Add(content);
    }
    #endregion

    #region 生成单元格
    private static PdfPCell GetPdfCell(string content, Font font, int horizontalAlignment)
    {

        Paragraph paragraph = new Paragraph(content, font);
        paragraph.FirstLineIndent = 2;
        paragraph.SetLeading(10, 20);
        paragraph.SpacingAfter = 10;

        PdfPCell cell = new PdfPCell(paragraph);
        cell.HorizontalAlignment = horizontalAlignment;//水平位置
        cell.VerticalAlignment = Element.ALIGN_CENTER;//垂直居中
        cell.MinimumHeight = 20;//单元格的最小高度
        cell.Border = 0;
        return cell;
    }
    #endregion

    #region 生成水印
    private static MemoryStream SetWaterMark(MemoryStream ms, string filePath, string waterMarkName, string waterMarkAddr = null)
    {
        MemoryStream msWater = new MemoryStream();
        PdfReader pdfReader = null;
        PdfStamper pdfStamper = null;
        try
        {
            pdfReader = new PdfReader(filePath);
            pdfStamper = new PdfStamper(pdfReader, msWater);

            int total = pdfReader.NumberOfPages + 1;//获取PDF的总页数
            iTextSharp.text.Rectangle psize = pdfReader.GetPageSize(1);//获取第一页
            float width = psize.Width;//PDF页面的宽度,用于计算水印倾斜
            float height = psize.Height;
            PdfContentByte waterContent;
            BaseFont basefont = BaseFont.CreateFont(@"C:\WINDOWS\Fonts\SIMFANG.TTF", BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
            PdfGState gs = new PdfGState();
            for (int i = 1; i < total; i++)
            {
                waterContent = pdfStamper.GetOverContent(i);//在内容上方加水印
                //透明度
                waterContent.SetGState(gs);
                //开始写入文本
                waterContent.BeginText();
                waterContent.SetColorFill(BaseColor.RED);
                waterContent.SetFontAndSize(basefont, 18);
                waterContent.SetTextMatrix(0, 0);
                if (waterMarkAddr == null || waterMarkAddr == "")
                {
                    waterContent.ShowTextAligned(Element.ALIGN_CENTER, waterMarkName, width / 2, height / 2, 55);
                }
                else
                {
                    waterContent.ShowTextAligned(Element.ALIGN_CENTER, waterMarkName, width / 2, height / 2 + 100, 55);
                    waterContent.ShowTextAligned(Element.ALIGN_CENTER, waterMarkAddr, width / 2, height / 2 - 100, 55);
                }
                waterContent.EndText();
            }
        }
        catch (Exception)
        {
            return ms;
        }
        finally
        {
            if (pdfStamper != null)
                pdfStamper.Close();

            if (pdfReader != null)
                pdfReader.Close();
        }
        return msWater;
    }
    #endregion

    //-----------------------发送PDF文件回浏览器端----------------------
    public static void SendFile(string fileName, MemoryStream ms, Encoding encoding = null)
    {
        fileName = (fileName + "").Replace(" ", "");
        encoding = encoding ?? Encoding.UTF8;
        if (ms != null && !string.IsNullOrEmpty(fileName))
        {
            System.Web.HttpResponse response = System.Web.HttpContext.Current.Response;
            response.Clear();
            response.Charset = encoding.BodyName;// "utf-8";
            if (!HttpContext.Current.Request.UserAgent.Contains("Firefox") && !HttpContext.Current.Request.UserAgent.Contains("Chrome"))
            {
                fileName = HttpUtility.UrlEncode(fileName, encoding);
            }
            response.AddHeader("Content-Disposition", "attachment;filename=" + fileName);
            //为了解决打开,导出NPOI生成的xlsx文件时,提示发现不可读取内容。
            if (!(fileName + "").ToLower().EndsWith(".xlsx"))
            {
                response.AddHeader("Content-Type", "application/octet-stream");
                response.BinaryWrite(ms.GetBuffer());
            }
            else
            {
                response.BinaryWrite(ms.ToArray());
            }
            ms.Close();
            ms = null;
            response.Flush();
            response.End();
        }
    }
}

特别需要注意一点的是,如果对字体有特殊要求,可以将字库文件放在项目目录下,但字库的文件类型不同,引用时略有差别。

ttc文件
BaseFont.CreateFont(@"C://Windows/Fonts/simsun.ttc,0", BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
  • 1
ttf文件
BaseFont.CreateFont(@"C://Windows/Fonts/simsun.ttf", BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
  • 1

这种模式的弊端在于调整文档的格式太痛苦了,你想按照预定的模板生成pdf,格式要按照他的机制一点点写,如果是篇幅比较长的文档,耐心和时间缺一不可。

在我埋头写了一天之后,同事路过看到我一脸狰狞,细问之,马上丢给我一个包,十分钟后搞定。没有广告,工具类马上贴上来。

本方法依赖于Aspose.Words,因为版权问题,不要直接用nuget引入,需要去网上down一个破解版。然后将需要生成的文件内容置于一个word中,相应参数用字符标识后,方便替换。最后加入以下工具类直接调用就OK了。

(破解dll可以在这里自取 链接: https://pan.baidu.com/s/1o7XpCqI 密码: kwpt)

CrackWord.cs
using System;
using System.Reflection;

class CrackWord
{
    /// <summary>
    /// 16.10.1.0
    /// </summary>
    public static void Crack()//使用前调用一次即可
    {
        string[] stModule = new string[8]
            {
                "\u000E\u2008\u200A\u2001",
                "\u000F\u2008\u200A\u2001",
                "\u0002\u200A\u200A\u2001",
                "\u000F",
                "\u0006",
                "\u000E",
                "\u0003",
                "\u0002"
            };
        Assembly assembly = Assembly.GetAssembly(typeof(Aspose.Words.License));

        Type typeLic = null, typeIsTrial = null, typeHelper = null;
        foreach (Type type in assembly.GetTypes())
        {
            if ((typeLic == null) && (type.Name == stModule[0]))
            {
                typeLic = type;
            }
            else if ((typeIsTrial == null) && (type.Name == stModule[1]))
            {
                typeIsTrial = type;
            }
            else if ((typeHelper == null) && (type.Name == stModule[2]))
            {
                typeHelper = type;
            }
        }
        if (typeLic == null || typeIsTrial == null || typeHelper == null)
        {
            throw new Exception();
        }
        object lic = Activator.CreateInstance(typeLic);
        int findCount = 0;

        foreach (FieldInfo field in typeLic.GetFields(BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance))
        {
            if (field.FieldType == typeLic && field.Name == stModule[3])
            {
                field.SetValue(null, lic);
                ++findCount;
            }
            else if (field.FieldType == typeof(DateTime) && field.Name == stModule[4])
            {
                field.SetValue(lic, DateTime.MaxValue);
                ++findCount;
            }
            else if (field.FieldType == typeIsTrial && field.Name == stModule[5])
            {
                field.SetValue(lic, 1);
                ++findCount;
            }

        }
        foreach (FieldInfo field in typeHelper.GetFields(BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance))
        {
            if (field.FieldType == typeof(bool) && field.Name == stModule[6])
            {
                field.SetValue(null, false);
                ++findCount;
            }
            if (field.FieldType == typeof(int) && field.Name == stModule[7])
            {
                field.SetValue(null, 128);
                ++findCount;
            }
        }
        if (findCount < 5)
        {
            throw new NotSupportedException("无效的版本");
        }
    }
}
ReplaceAndInsertImage.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Aspose.Words;
using Aspose.Words.Replacing;

public class ReplaceAndInsertImage : IReplacingCallback
{
    /// <summary>
    /// 需要插入的图片路径
    /// </summary>
    public string Url { get; set; }

    public ReplaceAndInsertImage(string url)
    {
        this.Url = url;
    }

    public ReplaceAction Replacing(ReplacingArgs e)
    {
        //获取当前节点
        var node = e.MatchNode;
        //获取当前文档
        Document doc = node.Document as Document;
        DocumentBuilder builder = new DocumentBuilder(doc);
        //将光标移动到指定节点
        builder.MoveTo(node);
        //插入图片
        builder.InsertImage(Url);
        return ReplaceAction.Replace;
    }
}
  • Cv.cs 调用生成类
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Aspose.Words;

public class Cv
{
    /// <summary>
    /// 生成录用offer文档
    /// </summary>
    /// <param name="source">模板文件</param>
    /// <param name="filespath">生成的PDF目录</param>
    /// <returns></returns>
    public static void Run(string source, string filespath,)
    {

        var dic = new Dictionary<string, string>();
       //替换模板文件的参数
        dic.Add("{xingming}","参数");
     
        CrackWord.Crack();
        Aspose.Words.Document doc = new Aspose.Words.Document(source);

        foreach (var key in dic.Keys)
        {
#pragma warning disable 618
            doc.Range.Replace(key, dic[key], false, false);
#pragma warning restore 618
        }

        doc.Save(filespath, SaveFormat.Pdf);
       
    }
}

source 为模板文件目录,本例中为word 文件。

posted on 2021-04-11 11:15  大西瓜3721  阅读(722)  评论(0编辑  收藏  举报

导航