Unity之创建与导出PDF

内容将会持续更新,有错误的地方欢迎指正,谢谢!

Unity之创建与导出PDF


|-----------------------------------------------------|
| TechX 坚持将创新的科技带给世界! 拥有更好的学习体验 ------ 不断努力,不断进步,不断探索 |

|-------------------------------------------------------------|
| TechX ------ 心探索、心进取! 助力快速掌握 PDF 的创建与导出 为初学者节省宝贵的学习时间,避免困惑! |

TechX 教程效果:


文章目录


一、第三方库iTextSharp导入

在Unity中生成PDF文件并写入内容,需要使用第三方库,因为Unity本身不提供直接操作PDF的API。一个常用的库是iTextSharp,这是一个强大的PDF处理库。iTextSharp是iText的C#版本,可以用于创建、修改和读取PDF文档。

1、通过Visual Studio的NuGet包管理器下载iTextSharp库

  1. 打开NuGet包管理器:

    在Visual Studio中,点击Tools菜单,选择NuGet Package Manager,然后选择Manage NuGet Packages for Solution...。

  2. 搜索iTextSharp:

    在打开的NuGet包管理器窗口中,点击Browse选项卡,然后在搜索框中输入iTextSharp。

  3. 安装iTextSharp:

    在搜索结果中找到iTextSharp包,点击Install按钮进行安装。根据提示完成安装过程。

2、导入DLL文件到Unity中

上一步下载的iTextSharp包在工程目录的Packages下,共包含两个文件夹:BouncyCastle.Cryptography.2.4.0和iTextSharp.5.5.13.4。

进入BouncyCastle.Cryptography.2.4.0\lib\net461和iTextSharp.5.5.13.4\lib\net461目录中找到BouncyCastle.Cryptography.dll和itextsharp.dll

将两个DLL文件复制到你的Unity项目的Assets/Plugins文件夹中。如果没有Plugins文件夹,可以创建一个。


二、使用iTextSharp生成和写入PDF文件的示例

在Unity项目中创建一个C#脚本,例如PDFGenerator.cs。

在脚本中使用iTextSharp来生成和写入PDF。

以下是完整的示例代码:

csharp 复制代码
using UnityEngine;
using System.IO;
using iTextSharp.text;
using iTextSharp.text.pdf;
using Image = iTextSharp.text.Image;

public class PDFGenerator : MonoBehaviour
{
    void Start()
    {
        // 设置PDF保存路径
        string path = Application.dataPath + "/GeneratedPDF.pdf";
        // 图片路径
        string imgPath = Application.streamingAssetsPath+ "/path_to_image.jpg";
        
        using (FileStream fileStream = new FileStream(path, FileMode.Create))
        {
	        // 创建一个文档对象
	        Document document = new Document();
	        
	        // 创建一个PDF写入流
	        PdfWriter pdfWriter = PdfWriter.GetInstance(document, fileStream );
	        
	        // 打开文档
	        document.Open();
	        
	        // 添加内容到文档
	        document.Add(new Paragraph("Hello, World!"));
	        document.Add(new Paragraph("This is a PDF generated in Unity."));
	        
	        // 添加图片
	        Image image = Image.GetInstance(imgPath );
	        document.Add(image);
	        
	        // 添加表格
	        PdfPTable table = new PdfPTable(3); // 3列的表格
	        table.AddCell("Cell 1");
	        table.AddCell("Cell 2");
	        document.Add(table);
	        
	        //关闭写入流
	        pdfWriter.Close();
	      	// 关闭文档
	        document.Close();
		}
        

        Debug.Log("PDF generated at: " + path);
    }
}

三、写入和导出PDF实战

我们将创建一个名为PDFOperation的类,用于封装PDF文档的创建和操作功能。

分步讲解:

  • 构造函数

    我们的PDFOperation类有三个构造函数,用于初始化PDF文档对象,可以指定页面大小和边距

  • 文档操作

    我们提供了一些方法来打开和关闭PDF文档,以及创建和关闭PDF写入流

  • 设置字体

    我们可以设置基础字体并创建字体对象,以便在文档中使用

  • 添加页面和段落

    我们可以添加新页面、空行和段落

  • 添加图片

    我们可以通过路径添加图片,并指定对齐方式和大小

  • 添加表格

    我们可以通过PdfPTable对象向PDF文档添加表格

csharp 复制代码
using System.IO;
using iTextSharp.text;
using iTextSharp.text.pdf;
using UnityEngine;
using Font = iTextSharp.text.Font;
using Rectangle = iTextSharp.text.Rectangle;

namespace PDFExport
{
    /// <summary>
    /// PDF文档操作类
    /// </summary>
    public class PDFOperation
    {
        #region 私有字段
        private Font font = default;
        private PdfWriter pdfWriter;
        private Rectangle documentSize;   //文档大小
        private Document document;//文档对象
        private BaseFont basefont;//字体
        #endregion

        #region 构造函数

        /// <summary>
        /// 构造函数
        /// </summary>
        public PDFOperation()
        {
            documentSize = PageSize.A4;
            document = new Document(documentSize);
        }

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="type">页面大小(如"A4")</param>
        public PDFOperation(Rectangle size)
        {
            documentSize = size;
            document = new Document(size);
        }

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="type">页面大小(如"A4")</param>
        /// <param name="marginLeft">内容距左边框距离</param>
        /// <param name="marginRight">内容距右边框距离</param>
        /// <param name="marginTop">内容距上边框距离</param>
        /// <param name="marginBottom">内容距下边框距离</param>
        public PDFOperation(Rectangle size, float marginLeft, float marginRight, float marginTop, float marginBottom)
        {
            documentSize = size;
            document = new Document(size, marginLeft, marginRight, marginTop, marginBottom);
        }

        #endregion


        #region 文档操作

        /// <summary>
        /// 创建写入流
        /// </summary>
        /// <param name="os">文档相关信息(如路径,打开方式等)</param>
        public PdfWriter OpenPdfWriter(FileStream os)
        {
            pdfWriter = PdfWriter.GetInstance(document, os);
            return pdfWriter;
        }

        /// <summary>
        /// 关闭写入流
        /// </summary>
        /// <param name="writer"></param>
        public void ClosePdfWriter()
        {
            pdfWriter.Close();
        }

        /// <summary>
        /// 打开文档
        /// </summary>
        public void Open()
        {
            document.Open();
        }

        /// <summary>
        /// 关闭打开的文档
        /// </summary>
        public void Close()
        {
            document.Close();
        }

        #endregion

        #region 设置字体

        /// <summary>
        /// 设置字体
        /// </summary>
        public void SetBaseFont(string path)
        {
            basefont = BaseFont.CreateFont(path, BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
        }

        /// <summary>
        /// 设置字体
        /// </summary>
        /// <param name="size">字体大小</param>
        public Font SetFont(float size)
        {
            font = new Font(basefont, size);
            return font;
        }

        /// <summary>
        /// 设置字体
        /// </summary>
        /// <param name="size"></param>
        /// <param name="style"></param>
        public Font SetFont(float size, int style)
        {
            font = new Font(basefont, size, style);
            return font;
        }

        /// <summary>
        /// 设置字体
        /// </summary>
        /// <param name="size"></param>
        /// <param name="style"></param>
        /// <param name="fontColor"></param>
        public Font SetFont(float size, int style, BaseColor fontColor)
        {
            font = new Font(basefont, size, style, fontColor);
            return font;
        }

        /// <summary>
        /// 获取字体
        /// </summary>
        /// <returns></returns>
        public Font GetFont()
        {
            return font;
        }

        #endregion

        public void AddPage()
        {
            document.NewPage();
        }

        #region 添加段落

        /// <summary>
        /// 空格
        /// 加入空行,用以区分上下行
        /// </summary>
        public void AddNullLine(int nullLine=1,int lightHeight=12)
        {
            // Change this to the desired number of empty lines
            int numberOfEmptyLines = nullLine; 
            for (int i = 0; i < numberOfEmptyLines; i++)
            {
                Paragraph emptyLine = new Paragraph(" ", new Font(Font.FontFamily.HELVETICA, lightHeight));
                document.Add(emptyLine);
            }
        }

        /// <summary>
        /// 插入文字内容
        /// </summary>
        /// <param name="content">内容</param>
        /// <param name="alignmentType">对齐格式,0为左对齐,1为居中</param>
        /// <param name="indent">首行缩进</param>
        public void AddParagraph(string content, int alignmentType = 0,float indent = 0)
        {
            Paragraph contentP = new Paragraph(new Chunk(content, font));
            contentP.FirstLineIndent = indent;
            contentP.Alignment = alignmentType;
            document.Add(contentP);
        }

        /// <summary>
        /// 添加段落
        /// </summary>
        /// <param name="content">内容</param>
        /// <param name="Alignment">对齐方式(1为居中,0为居左,2为居右)</param>
        /// <param name="SpacingAfter">段后空行数(0为默认值)</param>
        /// <param name="SpacingBefore">段前空行数(0为默认值)</param>
        /// <param name="MultipliedLeading">行间距(0为默认值)</param>
        public void AddParagraph(string content, int Alignment, float SpacingAfter, float SpacingBefore, float MultipliedLeading)
        {
            Paragraph pra = new Paragraph(content, font);
            pra.Alignment = Alignment;
            if (SpacingAfter != 0)
            {
                pra.SpacingAfter = SpacingAfter;
            }
            if (SpacingBefore != 0)
            {
                pra.SpacingBefore = SpacingBefore;
            }
            if (MultipliedLeading != 0)
            {
                pra.MultipliedLeading = MultipliedLeading;
            }
            document.Add(pra);
        }
        #endregion

        #region 添加图片

        /// <summary>
        /// 添加图片
        /// </summary>
        /// <param name="path">图片路径</param>
        /// <param name="Alignment">对齐方式(1为居中,0为居左,2为居右)</param>
        /// <param name="newWidth">图片宽(0为默认值,如果宽度大于页宽将按比率缩放)</param>
        /// <param name="newHeight">图片高</param>
        public Image AddImage(string imagePath, int Alignment, float newWidth, float newHeight)
        {
            if (!File.Exists(imagePath))
            {
                Debug.Log("该路径下不存在指定图片,请检测路径是否正确!");
                return null;
            }
            Image img = Image.GetInstance(imagePath);
            img.Alignment = Alignment;
            if (newWidth != 0)
            {
                img.ScaleAbsolute(newWidth, newHeight);
            }
            else
            {
                if (img.Width > PageSize.A4.Width)
                {
                    img.ScaleAbsolute(documentSize.Width, img.Width * img.Height / documentSize.Height);
                }
            }
            document.Add(img);
            return img;
        }

        /// <summary>
        /// 添加图片
        /// </summary>
        /// <param name="path">图片路径</param>
        /// <param name="Alignment">对齐方式(1为居中,0为居左,2为居右)</param>
        /// <param name="newWidth">图片宽</param>
        /// <param name="newHeight">图片高</param>
        public Image AddImage(string imagePath, int Alignment, int fitWidth, int fitHeight)
        {
            if (!File.Exists(imagePath))
            {
                Debug.Log("该路径下不存在指定图片,请检测路径是否正确!");
                return null;
            }
            Image image = Image.GetInstance(imagePath);
            image.ScaleToFit(fitWidth, fitHeight);
            image.Alignment = Alignment;
            document.Add(image);
            return image;
        }

        #endregion 

        #region Table表

        public void AddTable(PdfPTable table)
        {
            document.Add(table);
        }

        #endregion
    }
}

下面是一个使用PDFOperation类创建和导出PDF文档的完整示例。

通过上述类和方法,我们可以轻松创建带有页眉和页脚的实验报告PDF文件。

完整示例:

csharp 复制代码
using iTextSharp.text;
using iTextSharp.text.pdf;
using System;
using System.IO;
using UnityEditor;
using UnityEngine;
using Font = iTextSharp.text.Font;
using Image = iTextSharp.text.Image;

namespace PDFExport
{
    public class ReportExporterPDF: MonoBehaviour
    {
       private string fontPath = Application.streamingAssetsPath + "/Fonts/SIMFANG.TTF";
        string imagePath1 = Application.streamingAssetsPath + "/Images/logo.png";

        private void Start()
        {
            GenerateReportPDF();
        }

        public  void GenerateReportPDF()
        {
           CreatePDF(Application.streamingAssetsPath + "/Report.pdf");
        }


        private void CreatePDF(string filePath)
        {
           	using (FileStream fileStream = new FileStream(filePath, FileMode.Create))
            {
                PDFOperation pdf = new PDFOperation(PageSize.A4, 55f, 55f, 96f, 96f);
                pdf.SetBaseFont(fontPath);
                PdfWriter pdfWriter = pdf.OpenPdfWriter(fileStream);
                pdf.Open();

                HeaderFooterPageEvent headerFooterPageEvent = new HeaderFooterPageEvent(pdf,this);
                pdfWriter.PageEvent = headerFooterPageEvent;

                FirstPasge(pdf);

                pdf.Close();
                pdf.ClosePdfWriter();
#if UNITY_EDITOR
                AssetDatabase.Refresh();
#endif
            }
            Application.OpenURL(filePath);
        }

        #region FirstPage

        private void FirstPasge(PDFOperation pdf)
        {
            pdf.AddNullLine(1, 22);

            Image image1 = Image.GetInstance(imagePath1);

            PdfPTable table = new PdfPTable(1);

            table.DefaultCell.Border = Rectangle.NO_BORDER;
            table.DefaultCell.Padding = 0;
            table.DefaultCell.FixedHeight = 100;

            // 设置图片的缩放比例
            float scale = 0.9f;
            image1.ScaleAbsolute(image1.Width * scale, image1.Height * scale);
            PdfPCell cell1 = new PdfPCell(image1);
            cell1.HorizontalAlignment = 1;
            cell1.PaddingRight = 0;
            cell1.Border = Rectangle.NO_BORDER;
            table.AddCell(cell1);
            pdf.AddTable(table);

            pdf.AddNullLine();
            pdf.SetFont(24);
            pdf.AddParagraph("汽车实验系统", 1);

            pdf.AddNullLine();
            pdf.SetFont(36, Font.BOLD);
            pdf.AddParagraph("实验报告", 1);
            pdf.AddNullLine(3);
            AddMainInfo(pdf);
        }


        public void AddMainInfo(PDFOperation pdf)
        {
            // 创建一个有 2 列的表格
            float[] columnWidths = { 124, 369 };
            PdfPTable table = new PdfPTable(columnWidths);
            table.DefaultCell.Border = Rectangle.NO_BORDER;

            // 设置表格宽度和对齐方式
            table.WidthPercentage = 80;
            table.HorizontalAlignment = Element.ALIGN_CENTER;

            string[] cellContents = {
                "实验名称:", "汽车仿真实验",
                "实验地点:", "",
                "学生姓名:", "",
                "指导教师:", "",
                "所属单位:", "",
                "支持单位:", "XXXX科技大学",
                "支持单位:", "XXXXXX股份有限公司",
                "实验时间:", DateTime.Now.ToString("yyyy年MM月dd日")
            };

            // 用提供的信息添加表格单元格
            for (int i = 0; i < cellContents.Length; i++)
            {
                PdfPCell cell;
                if (i % 2 == 0)
                {
                    pdf.SetFont(14, Font.BOLD);
                    cell = new PdfPCell(new Phrase(cellContents[i], pdf.GetFont()));
                }
                else
                {
                    pdf.SetFont(14, Font.NORMAL);
                    cell = new PdfPCell(new Phrase(cellContents[i], pdf.GetFont()));
                }
                cell.Padding = 10;
                cell.Border = Rectangle.NO_BORDER;
                table.AddCell(cell);
            }

            pdf.AddTable(table);
        }
        #endregion

        #region  页眉页脚

        public class HeaderFooterPageEvent : PdfPageEventHelper
        {
            PDFOperation pdf;
            ReportExporterPDF reportExporter;
            public HeaderFooterPageEvent(PDFOperation pdf, ReportExporterPDF reportExporter)
            {
                this.pdf = pdf;
                this.reportExporter = reportExporter;
            }

            public override void OnEndPage(PdfWriter writer, Document doc)
            {
                base.OnEndPage(writer, doc);

                Header(writer, doc);
                Footer(writer, doc);
            }

            private void Header(PdfWriter writer, Document doc)
            {
                float[] columnWidths = { 25, 200 };

                // 添加带图片和文字的页眉
                PdfPTable headerTable = new PdfPTable(columnWidths);
                headerTable.DefaultCell.Border = Rectangle.NO_BORDER;
                headerTable.WidthPercentage = 100;
                headerTable.HorizontalAlignment = Element.ALIGN_CENTER;

                headerTable.TotalWidth = doc.PageSize.Width - doc.LeftMargin - doc.RightMargin; // Set table width
                headerTable.LockedWidth = true; // Lock the table width

                Image image1 = Image.GetInstance(reportExporter.imagePath1);

                // Add images to the header
                image1.ScaleAbsolute(image1.Width / 2, image1.Height / 2);
                PdfPCell imageCell1 = new PdfPCell(image1);
                imageCell1.Border = Rectangle.NO_BORDER;

                // Add text to the header
                pdf.SetFont(10, Font.NORMAL, BaseColor.GRAY);
                Font headerFont = pdf.GetFont();

                PdfPCell textCell = new PdfPCell(new Phrase("XXXXXX股份有限公司", headerFont));
                textCell.HorizontalAlignment = Element.ALIGN_RIGHT;
                textCell.VerticalAlignment = Element.ALIGN_BOTTOM;
                textCell.Border = Rectangle.NO_BORDER;

                headerTable.AddCell(imageCell1);
                headerTable.AddCell(textCell);

                headerTable.WriteSelectedRows(0, -1, doc.Left, doc.Top + 60, writer.DirectContent);
            }

            private void Footer(PdfWriter writer, Document doc)
            {
                // Add footer with page number
                PdfPTable footerTable = new PdfPTable(1);
                footerTable.DefaultCell.Border = Rectangle.NO_BORDER;
                footerTable.WidthPercentage = 100;
                footerTable.HorizontalAlignment = Element.ALIGN_CENTER;
                footerTable.TotalWidth = doc.PageSize.Width - doc.LeftMargin - doc.RightMargin; // Set table width
                footerTable.LockedWidth = true; // Lock the table width

                int pageNumber = writer.PageNumber;
                int totalPages = writer.CurrentPageNumber; // Exclude the cover page

                pdf.SetFont(9, Font.NORMAL, BaseColor.GRAY);
                Font footFont = pdf.GetFont();
                PdfPCell footerCell = new PdfPCell(new Phrase($"{totalPages}", footFont));
                footerCell.HorizontalAlignment = Element.ALIGN_CENTER;
                footerCell.Border = Rectangle.NO_BORDER;

                footerTable.AddCell(footerCell);

                footerTable.WriteSelectedRows(0, -1, doc.Left, doc.Bottom - 50, writer.DirectContent);
            }
        }
        #endregion
    }
}

|-----------------------------------------------|
| TechX ------ 心探索、心进取! 每一次跌倒都是一次成长 每一次努力都是一次进步 |


END 感谢您阅读本篇博客!希望这篇内容对您有所帮助。如果您有任何问题或意见,或者想要了解更多关于本主题的信息,欢迎在评论区留言与我交流。我会非常乐意与大家讨论和分享更多有趣的内容。
如果您喜欢本博客,请点赞和分享给更多的朋友,让更多人受益。同时,您也可以关注我的博客,以便及时获取最新的更新和文章。
在未来的写作中,我将继续努力,分享更多有趣、实用的内容。再次感谢大家的支持和鼓励,期待与您在下一篇博客再见!

相关推荐
晨欣2 小时前
Elasticsearch和Lucene之间是什么关系?(ChatGPT回答)
elasticsearch·chatgpt·lucene
小春熙子4 小时前
Unity图形学之Shader结构
unity·游戏引擎·技术美术
一个处女座的程序猿4 小时前
LLMs之PDF:zeroX(一款PDF到Markdown 的视觉模型转换工具)的简介、安装和使用方法、案例应用之详细攻略
pdf·markdown·zerox
Dxy12393102165 小时前
python下载pdf
数据库·python·pdf
周亚鑫5 小时前
vue3 pdf base64转成文件流打开
前端·javascript·pdf
Sitarrrr6 小时前
【Unity】ScriptableObject的应用和3D物体跟随鼠标移动:鼠标放置物体在场景中
3d·unity
极梦网络无忧6 小时前
Unity中IK动画与布偶死亡动画切换的实现
unity·游戏引擎·lucene
一名技术极客6 小时前
Vue2 doc、excel、pdf、ppt、txt、图片以及视频等在线预览
pdf·powerpoint·excel·文件在线预览
逐·風14 小时前
unity关于自定义渲染、内存管理、性能调优、复杂物理模拟、并行计算以及插件开发
前端·unity·c#
_oP_i16 小时前
Unity Addressables 系统处理 WebGL 打包本地资源的一种高效方式
unity·游戏引擎·webgl