跳至页脚内容
产品比较

IronPDF 与 `GrapeCity` PDF:.NET PDF 库对比

IronPDF 专注于使用 Chrome V8 渲染引擎为 .NET 应用程序生成 HTML 到 PDF 文件,而GrapeCity PDF 则专注于 PDF 查看和注释功能,因此 IronPDF 是需要具备完整 PDF 创建功能和现代 Web 内容支持的开发人员的更佳选择。

PDF 代表可携带文档格式。 它是一种允许在多种不同设备上以常规方式查看文档的文件类型。 PDF 通常用于与潜在雇主分享重要文档,如简历,或与客户分享发票。

尽管PDF格式很受欢迎,但它也存在一些局限性。 例如,您无法通过电子邮件共享 PDF 文件,收件人需要 PDF 阅读器才能打开。 PDF文件在移动设备上的显示效果可能不如Word文档清晰。 此外,与 Word 文档不同,PDF 需要编辑软件才能修改或更新内容。 但是,PDF 文件在所有设备上(无论是 PC 还是 Mac)都能保持一致的外观。 这种可靠性使得 PDF 成为一种标准格式,而其他文档类型(如 JPEG 或 GIF)则不具备这种可靠性。

在本文中,我们将回顾两个 .NET PDF 库:

  • IronPDF
  • GrapeCity PDF

IronPDF是什么?它与GrapeCity相比如何?

IronPDF是一个 .NET 库,提供用于创建、读取和操作 PDF 文档的功能,且代码量极少。 本文演示如何使用 IronPDF 创建 PDF 文件。 你需要具备 Visual Studio 或 C# 的基本知识以及 HTML 的工作知识。

您需要 Visual Studio 来编写、编译和运行应用程序,C# 来编写逻辑和代码,以及 HTML 来格式化 PDF 文件,包括标题、副标题、图像和段落。IronPDF 完全支持.NET Core 、.NET 5、.NET Framework 和 .NET Standard。 对于ASP.NET 应用程序,IronPDF 提供将网页转换为 PDF 的流畅集成。

只要具备基本的 C# 和 HTML 知识,就可以用最少的代码在 C# 中创建 PDF 文件。 访问IronPDF 官方功能页面了解更多信息。 对于程序化 PDF 创建,IronPDF 提供了除基本 HTML 转换之外的广泛功能。

如何在我的.NET项目中安装IronPDF?

开发解决方案需要安装IronPDF NuGet 包。 从菜单栏点击"项目"。 从下拉菜单中选择"管理NuGet 程序包"。 有关详细说明,请参阅安装概述。 此窗口将显示:

NuGet Package Manager window in Visual Studio showing no search results for IronPdf package

在 NuGet 包管理器界面搜索 IronPdf 时显示空搜索结果,表明该包可能不可用或存在连接问题。

选择"浏览"即可查看此窗口:

NuGet Package Manager interface in Visual Studio showing popular .NET packages including Entity Framework Core, Newtonsoft.Json, and Microsoft.Extensions.`DependencyInjection` with their version numbers and download counts.

NuGet 包管理器可以轻松访问必要的 .NET 库,其中 Entity Framework Core 和 Newtonsoft.Json 分别是数据库操作和 JSON 处理中最流行的包之一。

在搜索框中输入"IronPdf",然后按"回车"键。有关高级安装选项(包括特定于平台的配置),请查阅文档。 你应该看看:

NuGet Package Manager showing search results for IronPDF packages, including the main IronPDF library with 1.87M downloads and related rendering assets packages.

NuGet 包管理器界面显示可供安装的各种 IronPDF 包,每个包都会显示下载次数和版本号。

选择 IronPDF:

NuGet Package Manager showing IronPDF installation options alongside competing PDF libraries including PDFCore and other IronPDF rendering packages

NuGet 程序包管理器界面显示 IronPDF(版本 2021.3.1)为选定的安装程序包,并列出了其他 PDF 库以供比较,包括 PDFCore 和各种 IronPDF 渲染资源。

点击"安装"。 安装成功后,您将看到:

Visual Studio dialog showing IronPDF package installation with dependencies including IronPdf.2021.3.1 and related packages.

Visual Studio 中的 IronPDF 安装过程,展示了 NuGet 包管理器如何安装 IronPDF 版本 2021.3.1 及其依赖项。

按"确定"完成安装。 IronPDF 支持Windows 平台,包括 Windows 10、11 和服务器版本。 该库还支持LinuxmacOS ,可用于跨平台开发。

如何使用 IronPDF 创建 PDF 文件?

在文件顶部添加 IronPdf 命名空间。VB.NET开发人员也可以使用类似的功能:

using IronPdf;
using IronPdf;
$vbLabelText   $csharpLabel

您需要指定文件路径来存储生成的PDF文件。 使用SaveFileDialog提示用户输入文件名和路径。 对于高级应用场景,可将 PDF 文件导出到内存流而不保存到磁盘:

private void Save_Click(object sender, EventArgs e)
{
    // Code to Select the folder and save the file.
    SaveFileDialog saveFileDialog1 = new SaveFileDialog();
    saveFileDialog1.InitialDirectory = @"D:\";
    saveFileDialog1.Title = "Save Pdf File";
    saveFileDialog1.DefaultExt = "pdf";
    saveFileDialog1.Filter = "Pdf files (*.pdf)|*.pdf|All files (*.*)|*.*";
    saveFileDialog1.FilterIndex = 2;
    saveFileDialog1.RestoreDirectory = true;
    if (saveFileDialog1.ShowDialog() == DialogResult.OK)
    {
        string filename = saveFileDialog1.FileName;
        // actual code that will create Pdf files
        var HtmlLine = new HtmlToPdf();
        HtmlLine.RenderHtmlAsPdf(PdfText.Text).SaveAs(filename);
        // MessageBox to display that file save
        MessageBox.Show("File Saved Successfully!");
    }
}
private void Save_Click(object sender, EventArgs e)
{
    // Code to Select the folder and save the file.
    SaveFileDialog saveFileDialog1 = new SaveFileDialog();
    saveFileDialog1.InitialDirectory = @"D:\";
    saveFileDialog1.Title = "Save Pdf File";
    saveFileDialog1.DefaultExt = "pdf";
    saveFileDialog1.Filter = "Pdf files (*.pdf)|*.pdf|All files (*.*)|*.*";
    saveFileDialog1.FilterIndex = 2;
    saveFileDialog1.RestoreDirectory = true;
    if (saveFileDialog1.ShowDialog() == DialogResult.OK)
    {
        string filename = saveFileDialog1.FileName;
        // actual code that will create Pdf files
        var HtmlLine = new HtmlToPdf();
        HtmlLine.RenderHtmlAsPdf(PdfText.Text).SaveAs(filename);
        // MessageBox to display that file save
        MessageBox.Show("File Saved Successfully!");
    }
}
$vbLabelText   $csharpLabel

SaveFileDialog打开一个对话框,用于选择文件夹和文件名。 初始目录默认为D盘,但您可以更改它。 DefaultExtension设置为 PDF。 如需了解完整的转换选项,请参阅HTML 转 PDF 教程

"if"条件语句包含创建PDF的代码。 只需两行代码即可生成 PDF 文件。 PdfText是包含 PDF 内容的富文本框的名称。 文件名是SaveFileDialog中选择的文件路径。 对于 Web 应用程序,IronPDF 支持URL 到 PDF 的转换ASPX 到 PDF 的转换

如何使用 IronPDF 阅读 PDF 文件?

使用 IronPDF 读取 PDF 文件只需要两行代码。 如需了解高级提取功能,请参阅提取文本和图像指南

添加以下导入语句:

using IronPdf;
using System;
using System.Windows.Forms;
using IronPdf;
using System;
using System.Windows.Forms;
$vbLabelText   $csharpLabel

请将此代码写在您的函数内部。 IronPDF 提供PDF 解析功能PDF DOM 访问

private void Read_Click(object sender, EventArgs e)
{
    PdfDocument PDF = PdfDocument.FromFile(FilePath.Text);
    FileContent.Text = PDF.ExtractAllText();
}
private void Read_Click(object sender, EventArgs e)
{
    PdfDocument PDF = PdfDocument.FromFile(FilePath.Text);
    FileContent.Text = PDF.ExtractAllText();
}
$vbLabelText   $csharpLabel

此功能可将文档中的所有信息提取出来并发送给查看者。 报表组件使用此数据作为数据源。 IronPDF 支持从内存流读取 PDF 文件,并将PDF 文件转换为 HTML 格式以便在网页上显示。

GrapeCity PDF 提供哪些功能?

GrapeCity Documents 提供跨平台的常用格式文档管理。 .NET Standard 2.0 库无需 Adobe Acrobat 即可读取、生成、修改和保存 PDF 文件。 它提供字体支持、图像、图形、条形码、注释、轮廓、图章和水印。

有哪些PDF处理功能?

GrapeCity PDF 可为 .NET Standard 应用程序中的基本或复杂业务需求创建 PDF 文件。您可以从任何来源加载、修改和保存 PDF 文件。 IronPDF 提供完整的PDF 编辑功能,包括合并/拆分 PDF添加/删除页面旋转页面

我可以将PDF文件转换为图像吗?

GrapeCity PDF 使用最少的代码将 PDF 文件保存为图像,且不会造成质量损失。 IronPDF 提供将 PDF 栅格化为图像的功能,支持 PNG、JPEG 和 TIFF 格式。

GrapeCity是否包含PDF查看器组件?

GrapeCity Documents PDF Viewer 是一款轻量级的客户端查看器,支持标准 PDF 功能。 对于 .NET MAUI 开发人员来说,IronPDF 提供在 MAUI 应用程序中查看 PDF 的功能,包括导航和搜索功能。

支持哪些类型的功能?

GrapeCity PDF 可以创建包含文本、图形、照片、注释和轮廓的复杂 PDF 文件。 IronPDF 还扩展了这些功能,包括数字签名表单创建/填写水印元数据管理

如何安装GrapeCity PDF?

IronPDF 提供两种安装方式。对于容器化部署,IronPDF支持 Docker远程容器操作,以实现灵活的生成:

  1. 下载压缩后的源文件。
  2. 将文件解压到目录。
  3. 进入该目录。
  4. 执行run.cmd来构建示例,启动SupportApi服务,并打开 http://localhost:3003
  5. 详情请参阅readme.MD

如何安装WinForms版本?

请按照以下步骤安装WinForms Edition:

  • Download C1ControlPanel from GrapeCity's ComponentOne.
  • 使用ComponentOne C1ControlPanel.exe 打开ControlPanel (关闭 Visual Studio)。
  • 使用注册邮箱/密码登录。
  • 对于新用户:
    • 注册并创建账户。
    • 验证电子邮件地址。
    • 通过验证链接激活。
    • 如果愿意,可以匿名使用。
  • 选择"在WinForms版本中安装"磁贴。选中"所有版本"复选框即可安装所有版本。
`ComponentOne` product edition comparison showing six different editions including `WinForms`, WPF, MVC, MVC Core, Wijmo, and UWP editions with their descriptions and install options

`GrapeCity`'s `ComponentOne` offers multiple edition options tailored to different development platforms and frameworks, each with the option to install sample projects

  • 点击"安装"查看许可协议。 审核后接受。
  • 接受许可协议以查看设置页面。 验证目录路径并开始安装。
`ComponentOne` installation settings screen showing installation directory, samples directory, and options to join customer experience program and send system information

`ComponentOne` installation configuration screen with privacy and data collection options

  • 安装程序会在控制器安装过程中显示进度。 在此过程中无法取消。
  • 安装完成后,将显示"安装成功"屏幕。 显示当前已安装的版本。
`WinForms` Edition installation dialog showing download progress and install button for 65+ UI controls

The `WinForms` Edition installer interface displays a simple download progress bar and installation option for a suite of 65+ smart and effective UI controls designed for rapid Windows Forms development.

`ComponentOne` installation success screen showing version 20183.1.338 with View Log and Back buttons

The `ComponentOne` installation interface displays a successful installation message for version 20183.1.338, featuring navigation tabs for Products, Activities, License, and Support

如何使用GrapeCity创建 PDF 文件?

以下代码演示了GrapeCity基本 PDF 创建方法。 对于HTML 转 PDF(使用 JavaScript)响应式 CSS自定义页眉/页脚等高级功能,IronPDF 提供完整的解决方案:

using System;
using System.IO;
using System.Drawing;
using System.Text;
using GrapeCity.Documents.Text;
using GrapeCity.Documents.Common;
using GrapeCity.Documents.Drawing;
using GrapeCity.Documents.Pdf;
using GrapeCity.Documents.Pdf.Structure;
using GrapeCity.Documents.Pdf.MarkedContent;
using GrapeCity.Documents.Pdf.Graphics;
using GrapeCity.Documents.Pdf.Annotations;
using GCTEXT = GrapeCity.Documents.Text;
using GCDRAW = GrapeCity.Documents.Drawing;
namespace GcPdfWeb.Samples.Basics
{
    // This sample shows how to create a PDF/A-3u compliant document.
    public class PdfA
    {
        public void CreatePDF(Stream stream)
        {
            var doc = new GcPdfDocument();
            var date = new DateTime(1961, 4, 12, 6, 7, 0, DateTimeKind.Utc);

            // Mark the document as PDF/A-3u conformant:
            doc.ConformanceLevel = PdfAConformanceLevel.PdfA3u;

            var fnt = GCTEXT.Font.FromFile(Path.Combine("Resources", "Fonts", "arial.ttf"));
            var gap = 36;

            // PDF/A-3a requires all content to be tagged so create and populate StructElement when rendering:
            StructElement sePart = new StructElement("Part");
            doc.StructTreeRoot.Children.Add(sePart);

            TextLayout tl = null;
            // Add 3 pages with sample content tagged according to PDF/A rules:
            for (int pageNo = 1; pageNo <= 3; ++pageNo)
            {
                // add page
                var page = doc.Pages.Add();
                var g = page.Graphics;
                float y = 72;
                if (doc.Pages.Count == 1)
                {
                    // Create paragraph element:
                    var seParagraph = new StructElement("P") { DefaultPage = page };
                    // Add it to Part element:
                    sePart.Children.Add(seParagraph);

                    tl = g.CreateTextLayout();
                    tl.MarginAll = 72;
                    tl.MaxWidth = page.Size.Width;

                    tl.DefaultFormat.Font = fnt;
                    tl.DefaultFormat.FontBold = true;
                    tl.DefaultFormat.FontSize = 20;
                    tl.Append("PDF/A-3A Document");

                    // PerformLayout is done automatically in a new TextLayout or after a Clear():
                    //tl.PerformLayout(true);

                    // Draw TextLayout within tagged content:
                    g.BeginMarkedContent(new TagMcid("P", 0));
                    g.DrawTextLayout(tl, PointF.Empty);
                    g.EndMarkedContent();

                    y = tl.ContentRectangle.Bottom + gap;

                    seParagraph.ContentItems.Add(new McidContentItemLink(0));
                }

                // Add some sample paragraphs tagged according to PDF/A rules:
                for (int i = 1; i <= 3; ++i)
                {
                    // Create paragraph element:
                    var seParagraph = new StructElement("P") { DefaultPage = page };
                    // Add it to Part element:
                    sePart.Children.Add(seParagraph);

                    var sb = new StringBuilder();
                    sb.Append(string.Format("Paragraph {0} on page {1}: ", i, pageNo));
                    sb.Append(Common.Util.LoremIpsum(1, 2, 4, 5, 10));
                    var para = sb.ToString();

                    tl.Clear();
                    tl.DefaultFormat.FontSize = 14;
                    tl.DefaultFormat.FontBold = false;
                    tl.MarginTop = y;
                    tl.Append(para);

                    // Draw TextLayout within tagged content:
                    g.BeginMarkedContent(new TagMcid("P", i));
                    g.DrawTextLayout(tl, PointF.Empty);
                    g.EndMarkedContent();

                    y += tl.ContentHeight + gap;

                    // Add content item to paragraph StructElement:
                    seParagraph.ContentItems.Add(new McidContentItemLink(i));

                    // PDF/A-3 allows embedding files into document, but they should be associated with some document element
                    // add embedded file associated with seParagraph:
                    var ef1 = EmbeddedFileStream.FromBytes(doc, Encoding.UTF8.GetBytes(para));
                    // ModificationDate and MimeType should be specified in case of PDF/A:
                    ef1.ModificationDate = date;
                    ef1.MimeType = "text/plain";
                    var fn = string.Format("Page{0}_Paragraph{1}.txt", pageNo, i);
                    var fs1 = FileSpecification.FromEmbeddedStream(fn, ef1);
                    // UnicodeFile.FileName should be specified for PDF/A compliance:
                    fs1.UnicodeFile.FileName = fs1.File.FileName;
                    // Relationship should be specified in case of PDF/A:
                    fs1.Relationship = AFRelationship.Unspecified;
                    doc.EmbeddedFiles.Add(fn, fs1);
                    seParagraph.AssociatedFiles.Add(fs1);
                }
            }

            // PDF/A-3 allows transparency drawing in PDF file, add some:
            var gpage = doc.Pages [0].Graphics;
            gpage.FillRectangle(new RectangleF(20, 20, 200, 200), Color.FromArgb(40, Color.Red));

            // PDF/A-3 allows using FormXObjects, add one with transparency:
            var r = new RectangleF(0, 0, 144, 72);
            var fxo = new FormXObject(doc, r);
            var gfxo = fxo.Graphics;
            gfxo.FillRectangle(r, Color.FromArgb(40, Color.Violet));
            TextFormat tf = new TextFormat()
            {
                Font = fnt,
                FontSize = 16,
                ForeColor = Color.FromArgb(100, Color.Black),
            };
            gfxo.DrawString("FormXObject", tf, r, TextAlignment.Center, ParagraphAlignment.Center);
            gfxo.DrawRectangle(r, Color.Blue, 3);
            gpage.DrawForm(fxo, new RectangleF(300, 250, r.Width, r.Height), null, ImageAlign.ScaleImage);

            // PDF/A-3 allows using embedded files, but each embedded file must be associated with a document's element:
            EmbeddedFileStream ef = EmbeddedFileStream.FromFile(doc, Path.Combine("Resources", "WordDocs", "ProcurementLetter.docx"));
            // ModificationDate and MimeType should be specified for EmbeddedFile in PDF/A:
            ef.ModificationDate = date;
            ef.MimeType = "application/msword";
            var fs = FileSpecification.FromEmbeddedFile(ef);
            fs.UnicodeFile.FileName = fs.File.FileName;
            fs.Relationship = AFRelationship.Unspecified;
            doc.EmbeddedFiles.Add("ProcurementLetter.docx", fs);
            // Associate embedded file with the document:
            doc.AssociatedFiles.Add(fs);

            // Add an attachment associated with an annotation:
            var sa = new StampAnnotation()
            {
                UserName = "Minerva",
                Font = fnt,
                Rect = new RectangleF(300, 36, 220, 72),
            };
            sa.Flags |= AnnotationFlags.Print;
            // Use a FormXObject to represent the stamp annotation:
            var stampFxo = new FormXObject(doc, new RectangleF(PointF.Empty, sa.Rect.Size));
            var gstampFxo = stampFxo.Graphics;
            gstampFxo.FillRectangle(stampFxo.Bounds, Color.FromArgb(40, Color.Green));
            gstampFxo.DrawString("Stamp Annotation\nassociated with minerva.jpg", tf, stampFxo.Bounds, TextAlignment.Center, ParagraphAlignment.Center);
            gstampFxo.DrawRectangle(stampFxo.Bounds, Color.Green, 3);
            //
            sa.AppearanceStreams.Normal.Default = stampFxo;
            doc.Pages [0].Annotations.Add(sa);
            ef = EmbeddedFileStream.FromFile(doc, Path.Combine("Resources", "Images", "minerva.jpg"));
            ef.ModificationDate = date;
            ef.MimeType = "image/jpeg";
            fs = FileSpecification.FromEmbeddedFile(ef);
            fs.UnicodeFile.FileName = fs.File.FileName;
            fs.Relationship = AFRelationship.Unspecified;
            doc.EmbeddedFiles.Add("minerva.jpg", fs);
            sa.AssociatedFiles.Add(fs);

            // Mark the document as conforming to Tagged PDF conventions (required for PDF/A):
            doc.MarkInfo.Marked = true;

            // Metadata.CreatorTool and DocumentInfo.Creator should be the same for a PDF/A document:
            doc.Metadata.CreatorTool = doc.DocumentInfo.Creator;
            // A title should be specified for PDF/A document:
            doc.Metadata.Title = "GcPdf Document";
            doc.ViewerPreferences.DisplayDocTitle = true;

            // Done:
            doc.Save(stream);
        }
    }
}
using System;
using System.IO;
using System.Drawing;
using System.Text;
using GrapeCity.Documents.Text;
using GrapeCity.Documents.Common;
using GrapeCity.Documents.Drawing;
using GrapeCity.Documents.Pdf;
using GrapeCity.Documents.Pdf.Structure;
using GrapeCity.Documents.Pdf.MarkedContent;
using GrapeCity.Documents.Pdf.Graphics;
using GrapeCity.Documents.Pdf.Annotations;
using GCTEXT = GrapeCity.Documents.Text;
using GCDRAW = GrapeCity.Documents.Drawing;
namespace GcPdfWeb.Samples.Basics
{
    // This sample shows how to create a PDF/A-3u compliant document.
    public class PdfA
    {
        public void CreatePDF(Stream stream)
        {
            var doc = new GcPdfDocument();
            var date = new DateTime(1961, 4, 12, 6, 7, 0, DateTimeKind.Utc);

            // Mark the document as PDF/A-3u conformant:
            doc.ConformanceLevel = PdfAConformanceLevel.PdfA3u;

            var fnt = GCTEXT.Font.FromFile(Path.Combine("Resources", "Fonts", "arial.ttf"));
            var gap = 36;

            // PDF/A-3a requires all content to be tagged so create and populate StructElement when rendering:
            StructElement sePart = new StructElement("Part");
            doc.StructTreeRoot.Children.Add(sePart);

            TextLayout tl = null;
            // Add 3 pages with sample content tagged according to PDF/A rules:
            for (int pageNo = 1; pageNo <= 3; ++pageNo)
            {
                // add page
                var page = doc.Pages.Add();
                var g = page.Graphics;
                float y = 72;
                if (doc.Pages.Count == 1)
                {
                    // Create paragraph element:
                    var seParagraph = new StructElement("P") { DefaultPage = page };
                    // Add it to Part element:
                    sePart.Children.Add(seParagraph);

                    tl = g.CreateTextLayout();
                    tl.MarginAll = 72;
                    tl.MaxWidth = page.Size.Width;

                    tl.DefaultFormat.Font = fnt;
                    tl.DefaultFormat.FontBold = true;
                    tl.DefaultFormat.FontSize = 20;
                    tl.Append("PDF/A-3A Document");

                    // PerformLayout is done automatically in a new TextLayout or after a Clear():
                    //tl.PerformLayout(true);

                    // Draw TextLayout within tagged content:
                    g.BeginMarkedContent(new TagMcid("P", 0));
                    g.DrawTextLayout(tl, PointF.Empty);
                    g.EndMarkedContent();

                    y = tl.ContentRectangle.Bottom + gap;

                    seParagraph.ContentItems.Add(new McidContentItemLink(0));
                }

                // Add some sample paragraphs tagged according to PDF/A rules:
                for (int i = 1; i <= 3; ++i)
                {
                    // Create paragraph element:
                    var seParagraph = new StructElement("P") { DefaultPage = page };
                    // Add it to Part element:
                    sePart.Children.Add(seParagraph);

                    var sb = new StringBuilder();
                    sb.Append(string.Format("Paragraph {0} on page {1}: ", i, pageNo));
                    sb.Append(Common.Util.LoremIpsum(1, 2, 4, 5, 10));
                    var para = sb.ToString();

                    tl.Clear();
                    tl.DefaultFormat.FontSize = 14;
                    tl.DefaultFormat.FontBold = false;
                    tl.MarginTop = y;
                    tl.Append(para);

                    // Draw TextLayout within tagged content:
                    g.BeginMarkedContent(new TagMcid("P", i));
                    g.DrawTextLayout(tl, PointF.Empty);
                    g.EndMarkedContent();

                    y += tl.ContentHeight + gap;

                    // Add content item to paragraph StructElement:
                    seParagraph.ContentItems.Add(new McidContentItemLink(i));

                    // PDF/A-3 allows embedding files into document, but they should be associated with some document element
                    // add embedded file associated with seParagraph:
                    var ef1 = EmbeddedFileStream.FromBytes(doc, Encoding.UTF8.GetBytes(para));
                    // ModificationDate and MimeType should be specified in case of PDF/A:
                    ef1.ModificationDate = date;
                    ef1.MimeType = "text/plain";
                    var fn = string.Format("Page{0}_Paragraph{1}.txt", pageNo, i);
                    var fs1 = FileSpecification.FromEmbeddedStream(fn, ef1);
                    // UnicodeFile.FileName should be specified for PDF/A compliance:
                    fs1.UnicodeFile.FileName = fs1.File.FileName;
                    // Relationship should be specified in case of PDF/A:
                    fs1.Relationship = AFRelationship.Unspecified;
                    doc.EmbeddedFiles.Add(fn, fs1);
                    seParagraph.AssociatedFiles.Add(fs1);
                }
            }

            // PDF/A-3 allows transparency drawing in PDF file, add some:
            var gpage = doc.Pages [0].Graphics;
            gpage.FillRectangle(new RectangleF(20, 20, 200, 200), Color.FromArgb(40, Color.Red));

            // PDF/A-3 allows using FormXObjects, add one with transparency:
            var r = new RectangleF(0, 0, 144, 72);
            var fxo = new FormXObject(doc, r);
            var gfxo = fxo.Graphics;
            gfxo.FillRectangle(r, Color.FromArgb(40, Color.Violet));
            TextFormat tf = new TextFormat()
            {
                Font = fnt,
                FontSize = 16,
                ForeColor = Color.FromArgb(100, Color.Black),
            };
            gfxo.DrawString("FormXObject", tf, r, TextAlignment.Center, ParagraphAlignment.Center);
            gfxo.DrawRectangle(r, Color.Blue, 3);
            gpage.DrawForm(fxo, new RectangleF(300, 250, r.Width, r.Height), null, ImageAlign.ScaleImage);

            // PDF/A-3 allows using embedded files, but each embedded file must be associated with a document's element:
            EmbeddedFileStream ef = EmbeddedFileStream.FromFile(doc, Path.Combine("Resources", "WordDocs", "ProcurementLetter.docx"));
            // ModificationDate and MimeType should be specified for EmbeddedFile in PDF/A:
            ef.ModificationDate = date;
            ef.MimeType = "application/msword";
            var fs = FileSpecification.FromEmbeddedFile(ef);
            fs.UnicodeFile.FileName = fs.File.FileName;
            fs.Relationship = AFRelationship.Unspecified;
            doc.EmbeddedFiles.Add("ProcurementLetter.docx", fs);
            // Associate embedded file with the document:
            doc.AssociatedFiles.Add(fs);

            // Add an attachment associated with an annotation:
            var sa = new StampAnnotation()
            {
                UserName = "Minerva",
                Font = fnt,
                Rect = new RectangleF(300, 36, 220, 72),
            };
            sa.Flags |= AnnotationFlags.Print;
            // Use a FormXObject to represent the stamp annotation:
            var stampFxo = new FormXObject(doc, new RectangleF(PointF.Empty, sa.Rect.Size));
            var gstampFxo = stampFxo.Graphics;
            gstampFxo.FillRectangle(stampFxo.Bounds, Color.FromArgb(40, Color.Green));
            gstampFxo.DrawString("Stamp Annotation\nassociated with minerva.jpg", tf, stampFxo.Bounds, TextAlignment.Center, ParagraphAlignment.Center);
            gstampFxo.DrawRectangle(stampFxo.Bounds, Color.Green, 3);
            //
            sa.AppearanceStreams.Normal.Default = stampFxo;
            doc.Pages [0].Annotations.Add(sa);
            ef = EmbeddedFileStream.FromFile(doc, Path.Combine("Resources", "Images", "minerva.jpg"));
            ef.ModificationDate = date;
            ef.MimeType = "image/jpeg";
            fs = FileSpecification.FromEmbeddedFile(ef);
            fs.UnicodeFile.FileName = fs.File.FileName;
            fs.Relationship = AFRelationship.Unspecified;
            doc.EmbeddedFiles.Add("minerva.jpg", fs);
            sa.AssociatedFiles.Add(fs);

            // Mark the document as conforming to Tagged PDF conventions (required for PDF/A):
            doc.MarkInfo.Marked = true;

            // Metadata.CreatorTool and DocumentInfo.Creator should be the same for a PDF/A document:
            doc.Metadata.CreatorTool = doc.DocumentInfo.Creator;
            // A title should be specified for PDF/A document:
            doc.Metadata.Title = "GcPdf Document";
            doc.ViewerPreferences.DisplayDocTitle = true;

            // Done:
            doc.Save(stream);
        }
    }
}
$vbLabelText   $csharpLabel

与 IronPDF 相比, GrapeCity PDF 的功能有限。 IronPDF 支持PDF/A 合规性PDF/UA 可访问性自定义纸张尺寸高级渲染选项

IronPDF的许可模式和定价是什么?

30 天退款保证:购买许可证后,您将获得 30 天退款保证。 如果许可证不符合您的需求,IronPDF 将在 30 天内保证退款。

轻松集成:将 IronPDF 与正在运行的项目和您的环境集成是一个无缝过程,只需一行代码即可完成。 这可以在使用 NuGet 包方法集成或者直接在线下载并集成到您的环境中时实现。

永久授权:只需购买一次许可证,无需续费。

免费支持和产品更新:每个许可证都将附带来自产品团队的全方位支持,以及一年的免费产品更新。 可以随时购买扩展。 扩展可以在购买前查看。

立即发放许可证:收到付款后,立即发送已注册的许可证密钥。

所有许可均为永久性,可用于舞台搭建、开发和制作。

IronPDF 如何支持 Bootstrap 等现代 Web 框架?

现代 PDF 生成技术受益于可视化流程表示。 此 Bootstrap 5 示例演示了 IronPDF 在使用卡片、徽章和步骤指示器渲染工作流程时间线方面的能力。 如需完整的框架支持,请参阅Bootstrap 和 Flexbox 故障排除指南

using IronPdf;

var renderer = new ChromePdfRenderer();

string workflowTimeline = @"
<!DOCTYPE html>
<html>
<head>
    <meta charset='utf-8'>
    <link href='___PROTECTED_URL_66___ rel='stylesheet'>
    <style>
        .timeline-item { position: relative; padding-left: 40px; margin-bottom: 30px; }
        .timeline-item::before { content: ''; position: absolute; left: 0; top: 0; width: 20px; height: 20px;
            background: #0d6efd; border-radius: 50%; border: 3px solid white; box-shadow: 0 0 0 2px #0d6efd; }
        .timeline-item::after { content: ''; position: absolute; left: 9px; top: 20px; width: 2px; height: calc(100% + 10px);
            background: #dee2e6; }
        .timeline-item:last-child::after { display: none; }
        @media print { .timeline-item { page-break-inside: avoid; } }
    </style>
</head>
<body class='bg-light'>
    <div class='container py-4'>
        <div class='text-center mb-5'>
            <h1 class='display-6 fw-bold'>PDF Generation Workflow</h1>
            <p class='lead text-muted'>From HTML to Professional PDF Documents</p>
        </div>

        <div class='timeline-item'>
            <div class='card shadow-sm'>
                <div class='card-body'>
                    <div class='d-flex justify-content-between align-items-center mb-2'>
                        <h4 class='card-title mb-0'>Step 1: Initialize Renderer</h4>
                        <span class='badge bg-primary'>Setup</span>
                    </div>
                    <p class='card-text'>Create ChromePdfRenderer instance with Chrome V8 engine for accurate HTML rendering.</p>
                    <div class='bg-light p-2 rounded'>
                        <code>var renderer = new ChromePdfRenderer();</code>
                    </div>
                    <div class='mt-2'>
                        <small class='text-muted'>✓ Chrome V8 Engine • ✓ Full CSS3 Support • ✓ JavaScript Ready</small>
                    </div>
                </div>
            </div>
        </div>

        <div class='timeline-item'>
            <div class='card shadow-sm'>
                <div class='card-body'>
                    <div class='d-flex justify-content-between align-items-center mb-2'>
                        <h4 class='card-title mb-0'>Step 2: Prepare HTML Content</h4>
                        <span class='badge bg-info'>Content</span>
                    </div>
                    <p class='card-text'>Design your document using modern HTML5, CSS3 (Flexbox/Grid), and optional JavaScript.</p>
                    <div class='row g-2'>
                        <div class='col-4'><span class='badge bg-success w-100'>HTML5</span></div>
                        <div class='col-4'><span class='badge bg-success w-100'>CSS3</span></div>
                        <div class='col-4'><span class='badge bg-success w-100'>JavaScript</span></div>
                    </div>
                </div>
            </div>
        </div>

        <div class='timeline-item'>
            <div class='card shadow-sm'>
                <div class='card-body'>
                    <div class='d-flex justify-content-between align-items-center mb-2'>
                        <h4 class='card-title mb-0'>Step 3: Render to PDF</h4>
                        <span class='badge bg-warning text-dark'>Processing</span>
                    </div>
                    <p class='card-text'>Convert HTML to PDF with pixel-perfect accuracy and sub-second performance.</p>
                    <div class='bg-light p-2 rounded'>
                        <code>var pdf = renderer.RenderHtmlAsPdf(htmlContent);</code>
                    </div>
                    <div class='progress mt-2' style='height: 8px;'>
                        <div class='progress-bar bg-warning' style='width: 100%'></div>
                    </div>
                    <small class='text-muted d-block mt-1'>Average render time: 0.9 seconds</small>
                </div>
            </div>
        </div>

        <div class='timeline-item'>
            <div class='card shadow-sm'>
                <div class='card-body'>
                    <div class='d-flex justify-content-between align-items-center mb-2'>
                        <h4 class='card-title mb-0'>Step 4: Save or Stream</h4>
                        <span class='badge bg-success'>Output</span>
                    </div>
                    <p class='card-text'>Export to file, stream, or byte array for flexible deployment options.</p>
                    <div class='bg-light p-2 rounded'>
                        <code>pdf.SaveAs("document.pdf");</code>
                    </div>
                    <div class='mt-2'>
                        <span class='badge bg-outline-secondary me-1'>File</span>
                        <span class='badge bg-outline-secondary me-1'>Stream</span>
                        <span class='badge bg-outline-secondary'>Byte Array</span>
                    </div>
                </div>
            </div>
        </div>

        <div class='alert alert-info'>
            <strong>Comparison Note:</strong> GrapeCity PDF Viewer focuses on document viewing and annotation, not HTML-to-PDF generation. IronPDF specializes in creating PDFs from modern web content with full Bootstrap and framework support.
        </div>

        <div class='card shadow-sm border-primary'>
            <div class='card-header bg-primary text-white'>
                <h5 class='mb-0'>Key Advantages</h5>
            </div>
            <div class='card-body'>
                <div class='row'>
                    <div class='col-md-6'>
                        <h6 class='text-primary'>IronPDF Strengths</h6>
                        <ul class='small'>
                            <li>Complete HTML-to-PDF workflow</li>
                            <li>Bootstrap 5 framework support</li>
                            <li>Async/await for scalability</li>
                            <li>Cross-platform deployment</li>
                        </ul>
                    </div>
                    <div class='col-md-6'>
                        <h6 class='text-muted'>GrapeCity Focus</h6>
                        <ul class='small'>
                            <li>PDF viewing and annotation</li>
                            <li>UI component for display</li>
                            <li>Limited generation features</li>
                            <li>Viewer-centric approach</li>
                        </ul>
                    </div>
                </div>
            </div>
        </div>
    </div>
</body>
</html>";

var pdf = renderer.RenderHtmlAsPdf(workflowTimeline);
pdf.SaveAs("workflow-timeline.pdf");
using IronPdf;

var renderer = new ChromePdfRenderer();

string workflowTimeline = @"
<!DOCTYPE html>
<html>
<head>
    <meta charset='utf-8'>
    <link href='___PROTECTED_URL_66___ rel='stylesheet'>
    <style>
        .timeline-item { position: relative; padding-left: 40px; margin-bottom: 30px; }
        .timeline-item::before { content: ''; position: absolute; left: 0; top: 0; width: 20px; height: 20px;
            background: #0d6efd; border-radius: 50%; border: 3px solid white; box-shadow: 0 0 0 2px #0d6efd; }
        .timeline-item::after { content: ''; position: absolute; left: 9px; top: 20px; width: 2px; height: calc(100% + 10px);
            background: #dee2e6; }
        .timeline-item:last-child::after { display: none; }
        @media print { .timeline-item { page-break-inside: avoid; } }
    </style>
</head>
<body class='bg-light'>
    <div class='container py-4'>
        <div class='text-center mb-5'>
            <h1 class='display-6 fw-bold'>PDF Generation Workflow</h1>
            <p class='lead text-muted'>From HTML to Professional PDF Documents</p>
        </div>

        <div class='timeline-item'>
            <div class='card shadow-sm'>
                <div class='card-body'>
                    <div class='d-flex justify-content-between align-items-center mb-2'>
                        <h4 class='card-title mb-0'>Step 1: Initialize Renderer</h4>
                        <span class='badge bg-primary'>Setup</span>
                    </div>
                    <p class='card-text'>Create ChromePdfRenderer instance with Chrome V8 engine for accurate HTML rendering.</p>
                    <div class='bg-light p-2 rounded'>
                        <code>var renderer = new ChromePdfRenderer();</code>
                    </div>
                    <div class='mt-2'>
                        <small class='text-muted'>✓ Chrome V8 Engine • ✓ Full CSS3 Support • ✓ JavaScript Ready</small>
                    </div>
                </div>
            </div>
        </div>

        <div class='timeline-item'>
            <div class='card shadow-sm'>
                <div class='card-body'>
                    <div class='d-flex justify-content-between align-items-center mb-2'>
                        <h4 class='card-title mb-0'>Step 2: Prepare HTML Content</h4>
                        <span class='badge bg-info'>Content</span>
                    </div>
                    <p class='card-text'>Design your document using modern HTML5, CSS3 (Flexbox/Grid), and optional JavaScript.</p>
                    <div class='row g-2'>
                        <div class='col-4'><span class='badge bg-success w-100'>HTML5</span></div>
                        <div class='col-4'><span class='badge bg-success w-100'>CSS3</span></div>
                        <div class='col-4'><span class='badge bg-success w-100'>JavaScript</span></div>
                    </div>
                </div>
            </div>
        </div>

        <div class='timeline-item'>
            <div class='card shadow-sm'>
                <div class='card-body'>
                    <div class='d-flex justify-content-between align-items-center mb-2'>
                        <h4 class='card-title mb-0'>Step 3: Render to PDF</h4>
                        <span class='badge bg-warning text-dark'>Processing</span>
                    </div>
                    <p class='card-text'>Convert HTML to PDF with pixel-perfect accuracy and sub-second performance.</p>
                    <div class='bg-light p-2 rounded'>
                        <code>var pdf = renderer.RenderHtmlAsPdf(htmlContent);</code>
                    </div>
                    <div class='progress mt-2' style='height: 8px;'>
                        <div class='progress-bar bg-warning' style='width: 100%'></div>
                    </div>
                    <small class='text-muted d-block mt-1'>Average render time: 0.9 seconds</small>
                </div>
            </div>
        </div>

        <div class='timeline-item'>
            <div class='card shadow-sm'>
                <div class='card-body'>
                    <div class='d-flex justify-content-between align-items-center mb-2'>
                        <h4 class='card-title mb-0'>Step 4: Save or Stream</h4>
                        <span class='badge bg-success'>Output</span>
                    </div>
                    <p class='card-text'>Export to file, stream, or byte array for flexible deployment options.</p>
                    <div class='bg-light p-2 rounded'>
                        <code>pdf.SaveAs("document.pdf");</code>
                    </div>
                    <div class='mt-2'>
                        <span class='badge bg-outline-secondary me-1'>File</span>
                        <span class='badge bg-outline-secondary me-1'>Stream</span>
                        <span class='badge bg-outline-secondary'>Byte Array</span>
                    </div>
                </div>
            </div>
        </div>

        <div class='alert alert-info'>
            <strong>Comparison Note:</strong> GrapeCity PDF Viewer focuses on document viewing and annotation, not HTML-to-PDF generation. IronPDF specializes in creating PDFs from modern web content with full Bootstrap and framework support.
        </div>

        <div class='card shadow-sm border-primary'>
            <div class='card-header bg-primary text-white'>
                <h5 class='mb-0'>Key Advantages</h5>
            </div>
            <div class='card-body'>
                <div class='row'>
                    <div class='col-md-6'>
                        <h6 class='text-primary'>IronPDF Strengths</h6>
                        <ul class='small'>
                            <li>Complete HTML-to-PDF workflow</li>
                            <li>Bootstrap 5 framework support</li>
                            <li>Async/await for scalability</li>
                            <li>Cross-platform deployment</li>
                        </ul>
                    </div>
                    <div class='col-md-6'>
                        <h6 class='text-muted'>GrapeCity Focus</h6>
                        <ul class='small'>
                            <li>PDF viewing and annotation</li>
                            <li>UI component for display</li>
                            <li>Limited generation features</li>
                            <li>Viewer-centric approach</li>
                        </ul>
                    </div>
                </div>
            </div>
        </div>
    </div>
</body>
</html>";

var pdf = renderer.RenderHtmlAsPdf(workflowTimeline);
pdf.SaveAs("workflow-timeline.pdf");
$vbLabelText   $csharpLabel

输出:一个专业的流程时间线 PDF,带有 Bootstrap 5 卡片、徽章、进度条和自定义时间线样式。 IronPDF 准确渲染所有定位、flexbox 布局和实用程序类,展示了对复杂视觉设计的全面 CSS3 支持。

有关 Bootstrap 兼容性的详细信息,请参阅Bootstrap 和 Flexbox CSS 指南。 IronPDF 支持网页字体和图标,实现丰富的排版效果。

Lite套餐的价格是多少?

  • 1 开发人员
  • 1 个位置
  • 1 个项目
  • 永久许可证

该软件包允许一位开发人员在一个位置为单个应用程序使用 Iron Software。 许可证不可转让给外部组织或代理/客户关系。 不包括 OEM 再分发和未另行承保的 SaaS 使用。

定价:每年从$799起。

专业执照包含哪些内容?

  • 10 个开发人员
  • 10 个位置
  • 10 个项目
  • 永久许可证

此许可证允许十位开发人员在最多十个地点使用 Iron Software。 您可以将其用于无限数量的网站、内网应用程序或桌面软件。 许可证不得转让给组织外部人员。 不包括 OEM 再分发和未另行承保的 SaaS 使用。 最多可与 10 个项目集成。

定价:从每年 $1,199 开始。

无限许可有哪些好处?

  • 无限开发人员
  • 无限位置
  • 无限项目
  • 永久许可证

允许同一组织内无限数量的开发人员在无限数量的地点使用 Iron Software。 可用于无限数量的应用程序。 许可证不得转让给组织外部人员。 不包括 OEM 再分发和未另行承保的 SaaS 使用。

定价:每年起价为$2999。

免版税再分发:您可以根据基本许可涵盖的项目数量,将 Iron 软件作为几个不同包装的商业产品的一部分进行分发(无需支付版税)。 这将允许 Iron Software 在 SaaS 软件服务中部署,基于基础许可证涵盖的项目数量。

定价: 从每年$1599起。

IronPDF pricing tiers comparison showing Lite ($499), Professional ($999), and Unlimited ($2,999) licenses with different developer, location, and project limits

IronPDF 提供三种许可级别,其中专业版许可最受欢迎,售价 999 美元,包含 10 个开发人员、10 个地点和 10 个项目。

GrapeCity PDF的许可模式和定价是什么?

PDF许可文件包含哪些内容?

  • 包括 1 个开发人员许可证
  • 1 个分发地点

包含一个开发者许可证和一个分发位置,但不提供支持和维护。

定价:从每年 $1,199 开始。

什么是 Documents for PDF Unlimited?

  • 包括 1 个开发人员许可证
  • 无限分发地点

包含一个开发者许可证,分发地点不限。 不提供技术支持和维护。 GrapeCity不支持 SaaS 和 OEM。

定价:每年 2799 美元起。

Documents for PDF Team Unlimited 提供哪些服务?

  • 包括 5 个开发人员许可证
  • 无限分发地点

包含五个开发者许可证,分发地点不限。 不提供技术支持和维护。 GrapeCity不支持 SaaS 和 OEM。

定价:每年 5799 美元起。

Three pricing tiers for Documents for PDF software: basic at $999 per developer, Unlimited at $2799, and Team Unlimited at $5799, each with different license and distribution options.

`GrapeCity`'s Documents for PDF pricing structure offers three tiers to accommodate different development team sizes and distribution needs.

IronPDF Lite One-Developer 套餐包含 1 年的$799支持。 GrapeCity Documents for PDF One-Developer 软件包售价为$1,199不提供技术支持。 IronPDF 专业版套餐包含 10 位开发人员,并提供一年的支持服务,价格为$1,199 。 GrapeCity仅提供 5 人开发者套餐,售价 5799 美元。有关IronPDF 许可选项的更多信息,请访问官方许可页面。

IronPDF Lite 和 Professional 套餐包含 SaaS 服务、OEM 和 5 年支持选项。 包含五年支持、SaaS 和 OEM 的 Lite 单人开发者套餐GrapeCity 2897 美元。GrapeCity 不提供 SaaS、OEM 或五年支持。 Iron Professional 的 10 人开发者套餐包含 5 年支持、SaaS 和 OEM 服务GrapeCity售价 3397 美元。GrapeCity 没有 10 人开发者套餐选项。 了解长期支持的许可证延期升级选项

我的 .NET 项目应该选择哪个 PDF 库?

GrapeCity Documents for PDF 允许在桌面应用程序中导出/导入、创建AcroForms和执行 PDF。 但是,对于包括表单创建数字签名注释支持在内的完整 PDF 操作,IronPDF 提供了高级功能。

IronPDF 提供更高的精度。 竞争对手可能会遇到图像转换失败或出现未知字符等问题。 IronPDF 提供准确的结果。 Chrome 渲染引擎可确保像素级完美渲染,已通过像素级完美 HTML 转 PDF 指南进行验证。 如需优化,请参阅IronPDF 性能帮助指南

IronPDF 提供具有竞争力的许可和支持服务,且无需持续费用。 IronPDF 的起价为$799 ,包含完整的功能包。 GrapeCity PDF 的年费起价为 1649 美元。 IronPDF 支持多种平台,价格统一。对于企业级部署,IronPDF 提供异步和多线程功能,实现高性能生成。

您可以免费试用,体验所有功能。 购买全套 Iron Suite 产品,即可享受两件产品的价格,获得五件产品。 有关IronPDF 许可的详细信息,请访问 Iron Software 的Iron Suite 产品页面以获取完整的软件包信息。

请注意 GrapeCity Documents for PDF 是其各自所有者的注册商标。 本网站与GrapeCity Documents for PDF 无任何关联,也未获得其认可或赞助。 所有产品名称、徽标和品牌均为各自所有者的财产。 比较仅供参考,反映的是撰写时的公开信息。

常见问题解答

如何在 .NET 中将 HTML 转换为 PDF?

您可以使用 IronPDF 的 RenderHtmlAsPdf 方法将 HTML 字符串转换为 PDF。此外,您还可以使用 RenderHtmlFileAsPdf 方法将 HTML 文件转换为 PDF。

使用 NuGet 安装 PDF 库的步骤是什么?

要使用 NuGet 安装 IronPDF,请打开 Visual Studio,导航到“管理 NuGet 包”,搜索“IronPdf”,然后点击“安装”将其添加到您的项目中。

GrapeCity PDF 查看器的 .NET 替代方案是什么?

IronPDF 是 GrapeCity PDF 查看器的合适替代方案,提供用户友好的体验,并对 .NET Core、.NET 5、Framework 和 Standard 提供广泛支持。

如何使用 .NET 库创建和读取 PDF 文件?

使用 IronPDF,您可以通过包含 IronPdf 命名空间并使用 HtmlToPdf 类将 HTML 转换为 PDF 来创建 PDF。要读取 PDF,您可以使用 PdfDocument 类来访问和操作内容。

PDF 库提供哪些许可选项?

IronPDF 提供多种许可选项,包括单个开发人员的 Lite 包,最多 10 位开发人员的专业许可证,以及为团队提供的无限许可证,所有这些都具有永久许可证和支持选项。

为何应该选择 IronPDF 而不是其他 PDF 解决方案?

IronPDF 因其准确性、全面的功能、有竞争力的许可和广泛的支持选项而受到推荐。它在多个平台上提供支持,价格具有竞争力。

我可以在购买前试用 PDF 库吗?

是的,IronPDF 提供免费试用,让您在做出购买决策之前探索所有可用功能。此外,Iron Suite 套餐以折扣价提供对所有 Iron Software 产品的访问。

使用 PDF 文件有哪些缺点?

由于文件大小,PDF 通过电子邮件共享可能会比较困难,与 Word 文档相比,在移动设备上显示可能不清晰,并且需要特定软件进行编辑或更新。

Curtis Chau
技术作家

Curtis Chau 拥有卡尔顿大学的计算机科学学士学位,专注于前端开发,精通 Node.js、TypeScript、JavaScript 和 React。他热衷于打造直观且美观的用户界面,喜欢使用现代框架并创建结构良好、视觉吸引力强的手册。

除了开发之外,Curtis 对物联网 (IoT) 有浓厚的兴趣,探索将硬件和软件集成的新方法。在空闲时间,他喜欢玩游戏和构建 Discord 机器人,将他对技术的热爱与创造力相结合。