跳過到頁腳內容
產品比較

IronPDF與ITextPDF之比較

對於處理 PDF 的開發人員來說,擁有一個可靠的 PDF 生成和操作庫是非常重要的。 In the .NET ecosystem, two popular PDF libraries stand out – IronPDF and iTextPdf – each offering powerful tools to create, edit, and manage PDF documents. 本文根據功能能力、文件質量和定價政策對這些庫進行深入比較。

IronPDF 和 iTextPdf 的概述

IronPDF

IronPDF 是一個強大的 .NET PDF 管理庫,與各種 .NET 環境(Core 8、7、6、Framework 和更多)兼容。 它提供了全面的功能集,包括 HTML 到 PDF 的轉換、PDF 合併、加密和數位簽名。 IronPDF 的文件簡單明瞭,並且用戶可以獲得可靠的技術支持。 開發人員經常在 Stack Overflow 討論和其他源代碼共享平台中找到常見問題的解決方案。

iTextPdf

iTextPdf 是來自 iText 庫的高級 PDF 庫,適用於 Java 和 .NET (C#),專注於企業級文檔處理。 它同時以 AGPL 和商業許可證形式提供,為多種項目提供靈活性。 像 iTextPdf 這樣的 iText軟件具有高度的定制性,非常適合於複雜的 PDF 任務,如文件加密、數位簽名和表單創建。

跨平台兼容性

IronPDF 和 iTextPdf 均支持跨平台功能,使它們對於 .NET 中的各種應用需求都非常靈活。 以下是每個庫的兼容性分解。

IronPDF

  • .NET 版本:兼容 .NET Core(8、7、6、5、3.1+)、.NET Standard(2.0+)和 .NET Framework(4.6.2+)。
  • 應用環境:在 Windows、Linux、Mac、Docker、Azure 和 AWS 環境中無縫工作。
  • 支持的 IDE:適用於 Microsoft Visual Studio 和 JetBrains Rider & ReSharper。
  • 操作系統和處理器:支持 Windows、Mac、Linux、x64、x86、ARM。

iTextPdf

  • .NET 版本:支持 .NET Core(2.x、3.x)、.NET Framework(4.6.1+)和 .NET 5+。
  • 應用環境:兼容於 Windows、macOS、Linux 和 Docker。

關鍵功能比較:IronPDF 與 iTextPdf

以下是每個庫提供的關鍵功能的詳細比較。

IronPDF

  • HTML 到 PDF 的轉換:支持 HTML、CSS、JavaScript 和圖像。
  • PDF 操作:拆分、合併和編輯 PDF 文件。
  • 安全性:PDF 加密和解密功能。
  • 編輯:允許註釋、書簽和大綱。
  • 模板:應用頁眉、頁腳和頁碼。
  • 浮水印:使用 HTML/CSS 控製的文本和圖像水印。
  • PDF 蓋章:在 PDF 文件上添加圖像和文本蓋章。

更多關於IronPDF提供的廣泛功能集的信息,請訪問IronPDF 功能頁面

iTextPdf

  • PDF 創建:支持從頭開始創建 PDF 文件。
  • 表單:提供 PDF 表單的創建和編輯。
  • 數位簽名:簽署 PDF 文件。
  • 壓縮:優化 PDF 文件大小。
  • 內容提取:從 PDF 提取文本和圖像。
  • 自定義性:高度自定義用于複雜項目。

PDF 功能的比較:IronPDF 與 iTextPdf

HTML 到 PDF 轉換

兩個庫都支持 HTML 到 PDF 的轉換,但在方法和易用性上有所不同。

IronPDF

using IronPdf;

// Instantiate the renderer
var renderer = new ChromePdfRenderer();

// Create a PDF from an HTML string
var pdf = renderer.RenderHtmlAsPdf("<h1>Hello World</h1>");
pdf.SaveAs("output.pdf");

// Advanced example with external assets
var myAdvancedPdf = renderer.RenderHtmlAsPdf("<img src='icons/iron.png'>", @"C:\site\assets\");
myAdvancedPdf.SaveAs("html-with-assets.pdf");
using IronPdf;

// Instantiate the renderer
var renderer = new ChromePdfRenderer();

// Create a PDF from an HTML string
var pdf = renderer.RenderHtmlAsPdf("<h1>Hello World</h1>");
pdf.SaveAs("output.pdf");

// Advanced example with external assets
var myAdvancedPdf = renderer.RenderHtmlAsPdf("<img src='icons/iron.png'>", @"C:\site\assets\");
myAdvancedPdf.SaveAs("html-with-assets.pdf");
Imports IronPdf

' Instantiate the renderer
Private renderer = New ChromePdfRenderer()

' Create a PDF from an HTML string
Private pdf = renderer.RenderHtmlAsPdf("<h1>Hello World</h1>")
pdf.SaveAs("output.pdf")

' Advanced example with external assets
Dim myAdvancedPdf = renderer.RenderHtmlAsPdf("<img src='icons/iron.png'>", "C:\site\assets\")
myAdvancedPdf.SaveAs("html-with-assets.pdf")
$vbLabelText   $csharpLabel

iTextPdf

using iText.Html2pdf;
using System.IO;

public class HtmlToPdf
{
    public static void ConvertHtmlToPdf()
    {
        using (FileStream htmlSource = File.Open("input.html", FileMode.Open))
        using (FileStream pdfDest = File.Open("output.pdf", FileMode.Create))
        {
            ConverterProperties converterProperties = new ConverterProperties();
            HtmlConverter.ConvertToPdf(htmlSource, pdfDest, converterProperties);
        }
    }
}
using iText.Html2pdf;
using System.IO;

public class HtmlToPdf
{
    public static void ConvertHtmlToPdf()
    {
        using (FileStream htmlSource = File.Open("input.html", FileMode.Open))
        using (FileStream pdfDest = File.Open("output.pdf", FileMode.Create))
        {
            ConverterProperties converterProperties = new ConverterProperties();
            HtmlConverter.ConvertToPdf(htmlSource, pdfDest, converterProperties);
        }
    }
}
Imports iText.Html2pdf
Imports System.IO

Public Class HtmlToPdf
	Public Shared Sub ConvertHtmlToPdf()
		Using htmlSource As FileStream = File.Open("input.html", FileMode.Open)
		Using pdfDest As FileStream = File.Open("output.pdf", FileMode.Create)
			Dim converterProperties As New ConverterProperties()
			HtmlConverter.ConvertToPdf(htmlSource, pdfDest, converterProperties)
		End Using
		End Using
	End Sub
End Class
$vbLabelText   $csharpLabel

IronPDF 提供了一種直接的 HTML 到 PDF 轉換方法,包括支持 HTML、CSS 和 JavaScript。 它允許用戶直接從 HTML 字符串轉換或包括資產與可選的基礎路徑。 iTextPdf 雖然有效,但需要更多的設置,更專注於基於文件的轉換。

加密 PDF 文件

在安全性至關重要的情況下,加密是必不可少的。 以下是每個資料庫的處理方式。

IronPDF

using IronPdf;

// Load an encrypted PDF or create a new one
var pdf = PdfDocument.FromFile("encrypted.pdf", "password");

// Set document security settings
pdf.SecuritySettings.MakePdfDocumentReadOnly("secret-key");
pdf.SecuritySettings.AllowUserCopyPasteContent = false;
pdf.Password = "my-password";
pdf.SaveAs("secured.pdf");
using IronPdf;

// Load an encrypted PDF or create a new one
var pdf = PdfDocument.FromFile("encrypted.pdf", "password");

// Set document security settings
pdf.SecuritySettings.MakePdfDocumentReadOnly("secret-key");
pdf.SecuritySettings.AllowUserCopyPasteContent = false;
pdf.Password = "my-password";
pdf.SaveAs("secured.pdf");
Imports IronPdf

' Load an encrypted PDF or create a new one
Private pdf = PdfDocument.FromFile("encrypted.pdf", "password")

' Set document security settings
pdf.SecuritySettings.MakePdfDocumentReadOnly("secret-key")
pdf.SecuritySettings.AllowUserCopyPasteContent = False
pdf.Password = "my-password"
pdf.SaveAs("secured.pdf")
$vbLabelText   $csharpLabel

iTextPdf

using iText.Kernel.Pdf;
using System.Text;

public class EncryptPdf
{
    public static readonly string DEST = "encrypt_pdf.pdf";
    public static readonly string OWNER_PASSWORD = "World";
    public static readonly string USER_PASSWORD = "Hello";

    protected void ManipulatePdf(string dest)
    {
        PdfDocument document = new PdfDocument(new PdfReader("input.pdf"), new PdfWriter(dest,
            new WriterProperties().SetStandardEncryption(
                Encoding.UTF8.GetBytes(USER_PASSWORD),
                Encoding.UTF8.GetBytes(OWNER_PASSWORD),
                EncryptionConstants.ALLOW_PRINTING,
                EncryptionConstants.ENCRYPTION_AES_128)));
        document.Close();
    }
}
using iText.Kernel.Pdf;
using System.Text;

public class EncryptPdf
{
    public static readonly string DEST = "encrypt_pdf.pdf";
    public static readonly string OWNER_PASSWORD = "World";
    public static readonly string USER_PASSWORD = "Hello";

    protected void ManipulatePdf(string dest)
    {
        PdfDocument document = new PdfDocument(new PdfReader("input.pdf"), new PdfWriter(dest,
            new WriterProperties().SetStandardEncryption(
                Encoding.UTF8.GetBytes(USER_PASSWORD),
                Encoding.UTF8.GetBytes(OWNER_PASSWORD),
                EncryptionConstants.ALLOW_PRINTING,
                EncryptionConstants.ENCRYPTION_AES_128)));
        document.Close();
    }
}
Imports iText.Kernel.Pdf
Imports System.Text

Public Class EncryptPdf
	Public Shared ReadOnly DEST As String = "encrypt_pdf.pdf"
	Public Shared ReadOnly OWNER_PASSWORD As String = "World"
	Public Shared ReadOnly USER_PASSWORD As String = "Hello"

	Protected Sub ManipulatePdf(ByVal dest As String)
		Dim document As New PdfDocument(New PdfReader("input.pdf"), New PdfWriter(dest, (New WriterProperties()).SetStandardEncryption(Encoding.UTF8.GetBytes(USER_PASSWORD), Encoding.UTF8.GetBytes(OWNER_PASSWORD), EncryptionConstants.ALLOW_PRINTING, EncryptionConstants.ENCRYPTION_AES_128)))
		document.Close()
	End Sub
End Class
$vbLabelText   $csharpLabel

IronPDF 的方法更為用戶友好,提供直接的 加密 和對於文件許可的控制。 iTextPdf 雖然有效,但需要詳盡的設置,注重加密標準。

PDF內容刪減

在 PDF 文件中消除信息對於隱私和安全至關重要。 以下是每個資料庫支持此功能的方式。

IronPDF

using IronPdf;

PdfDocument pdf = PdfDocument.FromFile("novel.pdf");

// Redact 'are' from all pages
pdf.RedactTextOnAllPages("are");
pdf.SaveAs("redacted.pdf");
using IronPdf;

PdfDocument pdf = PdfDocument.FromFile("novel.pdf");

// Redact 'are' from all pages
pdf.RedactTextOnAllPages("are");
pdf.SaveAs("redacted.pdf");
Imports IronPdf

Private pdf As PdfDocument = PdfDocument.FromFile("novel.pdf")

' Redact 'are' from all pages
pdf.RedactTextOnAllPages("are")
pdf.SaveAs("redacted.pdf")
$vbLabelText   $csharpLabel

iTextPdf

using iText.Kernel.Pdf;
using iText.Kernel.Colors;

// Define areas to redact on each page
Rectangle[] rectanglesToRedact = { new Rectangle(100, 100, 200, 50) };

// Draw black rectangles to cover sensitive areas
using (PdfDocument pdfDoc = new PdfDocument(new PdfReader("input.pdf"), new PdfWriter("output_redacted.pdf")))
{
    for (int pageNum = 1; pageNum <= pdfDoc.GetNumberOfPages(); pageNum++)
    {
        PdfPage page = pdfDoc.GetPage(pageNum);
        PdfCanvas canvas = new PdfCanvas(page);
        foreach (Rectangle rect in rectanglesToRedact)
        {
            canvas.SetFillColor(ColorConstants.BLACK)
                  .Rectangle(rect.GetX(), rect.GetY(), rect.GetWidth(), rect.GetHeight())
                  .Fill();
        }
    }
}
using iText.Kernel.Pdf;
using iText.Kernel.Colors;

// Define areas to redact on each page
Rectangle[] rectanglesToRedact = { new Rectangle(100, 100, 200, 50) };

// Draw black rectangles to cover sensitive areas
using (PdfDocument pdfDoc = new PdfDocument(new PdfReader("input.pdf"), new PdfWriter("output_redacted.pdf")))
{
    for (int pageNum = 1; pageNum <= pdfDoc.GetNumberOfPages(); pageNum++)
    {
        PdfPage page = pdfDoc.GetPage(pageNum);
        PdfCanvas canvas = new PdfCanvas(page);
        foreach (Rectangle rect in rectanglesToRedact)
        {
            canvas.SetFillColor(ColorConstants.BLACK)
                  .Rectangle(rect.GetX(), rect.GetY(), rect.GetWidth(), rect.GetHeight())
                  .Fill();
        }
    }
}
Imports iText.Kernel.Pdf
Imports iText.Kernel.Colors

' Define areas to redact on each page
Private rectanglesToRedact() As Rectangle = { New Rectangle(100, 100, 200, 50) }

' Draw black rectangles to cover sensitive areas
Using pdfDoc As New PdfDocument(New PdfReader("input.pdf"), New PdfWriter("output_redacted.pdf"))
	Dim pageNum As Integer = 1
	Do While pageNum <= pdfDoc.GetNumberOfPages()
		Dim page As PdfPage = pdfDoc.GetPage(pageNum)
		Dim canvas As New PdfCanvas(page)
		For Each rect As Rectangle In rectanglesToRedact
			canvas.SetFillColor(ColorConstants.BLACK).Rectangle(rect.GetX(), rect.GetY(), rect.GetWidth(), rect.GetHeight()).Fill()
		Next rect
		pageNum += 1
	Loop
End Using
$vbLabelText   $csharpLabel

IronPDF 提供了一種方便的 修訂工具,輕鬆隱藏所有頁面上的敏感文本。 相比之下,iTextPdf 要求用戶手動定義和應用黑色矩形,以遮蓋敏感區域。

能夠使用IronPDF數字簽署PDF文檔能夠節省時間,特別是將此設為自動化過程時。

自動簽署 PDF 文檔可以大大節省時間。以下是 IronPDF 和 iTextPdf 如何處理數位簽名的並排比較。

IronPDF

using IronPdf;
using IronPdf.Signing;
using System.Security.Cryptography.X509Certificates;

// Create X509Certificate2 object with X509KeyStorageFlags set to Exportable
X509Certificate2 cert = new X509Certificate2("IronSoftware.pfx", "123456", X509KeyStorageFlags.Exportable);

// Create PdfSignature object
var sig = new PdfSignature(cert);

// Sign PDF document
PdfDocument pdf = PdfDocument.FromFile("document.pdf");
pdf.Sign(sig);
pdf.SaveAs("signed.pdf");
using IronPdf;
using IronPdf.Signing;
using System.Security.Cryptography.X509Certificates;

// Create X509Certificate2 object with X509KeyStorageFlags set to Exportable
X509Certificate2 cert = new X509Certificate2("IronSoftware.pfx", "123456", X509KeyStorageFlags.Exportable);

// Create PdfSignature object
var sig = new PdfSignature(cert);

// Sign PDF document
PdfDocument pdf = PdfDocument.FromFile("document.pdf");
pdf.Sign(sig);
pdf.SaveAs("signed.pdf");
Imports IronPdf
Imports IronPdf.Signing
Imports System.Security.Cryptography.X509Certificates

' Create X509Certificate2 object with X509KeyStorageFlags set to Exportable
Private cert As New X509Certificate2("IronSoftware.pfx", "123456", X509KeyStorageFlags.Exportable)

' Create PdfSignature object
Private sig = New PdfSignature(cert)

' Sign PDF document
Private pdf As PdfDocument = PdfDocument.FromFile("document.pdf")
pdf.Sign(sig)
pdf.SaveAs("signed.pdf")
$vbLabelText   $csharpLabel

iTextPdf

using System;
using System.IO;
using iText.Kernel.Pdf;
using iText.Signatures;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Pkcs;
using Org.BouncyCastle.X509;

class Program
{
    static void Main(string[] args)
    {
        string src = "input.pdf";
        string dest = "output_signed.pdf";
        string pfxFile = "your_certificate.pfx";
        string pfxPassword = "your_password";

        try
        {
            // Load your certificate
            Pkcs12Store ks = new Pkcs12Store(new FileStream(pfxFile, FileMode.Open), pfxPassword.ToCharArray());
            string alias = null;
            foreach (string al in ks.Aliases)
            {
                if (ks.IsKeyEntry(al))
                {
                    alias = al;
                    break;
                }
            }
            ICipherParameters pk = ks.GetKey(alias).Key;
            X509CertificateEntry[] chain = ks.GetCertificateChain(alias);
            X509Certificate2 cert = new X509Certificate2(chain[0].Certificate.GetEncoded());

            // Create output PDF with signed content
            using (PdfReader reader = new PdfReader(src))
            {
                using (PdfWriter writer = new PdfWriter(dest))
                {
                    using (PdfDocument pdfDoc = new PdfDocument(reader, writer))
                    {
                        // Create the signer
                        PdfSigner signer = new PdfSigner(pdfDoc, writer, new StampingProperties().UseAppendMode());

                        // Configure signature appearance
                        PdfSignatureAppearance appearance = signer.GetSignatureAppearance();
                        appearance.SetReason("Digital Signature");
                        appearance.SetLocation("Your Location");
                        appearance.SetContact("Your Contact");

                        // Create signature
                        IExternalSignature pks = new PrivateKeySignature(pk, "SHA-256");
                        signer.SignDetached(pks, chain, null, null, null, 0, PdfSigner.CryptoStandard.CMS);
                    }
                }
            }
            Console.WriteLine($"PDF digitally signed successfully: {dest}");
        }
        catch (Exception ex)
        {
            Console.WriteLine($"Error signing PDF: {ex.Message}");
        }
    }
}
using System;
using System.IO;
using iText.Kernel.Pdf;
using iText.Signatures;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Pkcs;
using Org.BouncyCastle.X509;

class Program
{
    static void Main(string[] args)
    {
        string src = "input.pdf";
        string dest = "output_signed.pdf";
        string pfxFile = "your_certificate.pfx";
        string pfxPassword = "your_password";

        try
        {
            // Load your certificate
            Pkcs12Store ks = new Pkcs12Store(new FileStream(pfxFile, FileMode.Open), pfxPassword.ToCharArray());
            string alias = null;
            foreach (string al in ks.Aliases)
            {
                if (ks.IsKeyEntry(al))
                {
                    alias = al;
                    break;
                }
            }
            ICipherParameters pk = ks.GetKey(alias).Key;
            X509CertificateEntry[] chain = ks.GetCertificateChain(alias);
            X509Certificate2 cert = new X509Certificate2(chain[0].Certificate.GetEncoded());

            // Create output PDF with signed content
            using (PdfReader reader = new PdfReader(src))
            {
                using (PdfWriter writer = new PdfWriter(dest))
                {
                    using (PdfDocument pdfDoc = new PdfDocument(reader, writer))
                    {
                        // Create the signer
                        PdfSigner signer = new PdfSigner(pdfDoc, writer, new StampingProperties().UseAppendMode());

                        // Configure signature appearance
                        PdfSignatureAppearance appearance = signer.GetSignatureAppearance();
                        appearance.SetReason("Digital Signature");
                        appearance.SetLocation("Your Location");
                        appearance.SetContact("Your Contact");

                        // Create signature
                        IExternalSignature pks = new PrivateKeySignature(pk, "SHA-256");
                        signer.SignDetached(pks, chain, null, null, null, 0, PdfSigner.CryptoStandard.CMS);
                    }
                }
            }
            Console.WriteLine($"PDF digitally signed successfully: {dest}");
        }
        catch (Exception ex)
        {
            Console.WriteLine($"Error signing PDF: {ex.Message}");
        }
    }
}
Imports System
Imports System.IO
Imports iText.Kernel.Pdf
Imports iText.Signatures
Imports Org.BouncyCastle.Crypto
Imports Org.BouncyCastle.Pkcs
Imports Org.BouncyCastle.X509

Friend Class Program
	Shared Sub Main(ByVal args() As String)
		Dim src As String = "input.pdf"
		Dim dest As String = "output_signed.pdf"
		Dim pfxFile As String = "your_certificate.pfx"
		Dim pfxPassword As String = "your_password"

		Try
			' Load your certificate
			Dim ks As New Pkcs12Store(New FileStream(pfxFile, FileMode.Open), pfxPassword.ToCharArray())
			Dim [alias] As String = Nothing
			For Each al As String In ks.Aliases
				If ks.IsKeyEntry(al) Then
					[alias] = al
					Exit For
				End If
			Next al
			Dim pk As ICipherParameters = ks.GetKey([alias]).Key
			Dim chain() As X509CertificateEntry = ks.GetCertificateChain([alias])
			Dim cert As New X509Certificate2(chain(0).Certificate.GetEncoded())

			' Create output PDF with signed content
			Using reader As New PdfReader(src)
				Using writer As New PdfWriter(dest)
					Using pdfDoc As New PdfDocument(reader, writer)
						' Create the signer
						Dim signer As New PdfSigner(pdfDoc, writer, (New StampingProperties()).UseAppendMode())

						' Configure signature appearance
						Dim appearance As PdfSignatureAppearance = signer.GetSignatureAppearance()
						appearance.SetReason("Digital Signature")
						appearance.SetLocation("Your Location")
						appearance.SetContact("Your Contact")

						' Create signature
						Dim pks As IExternalSignature = New PrivateKeySignature(pk, "SHA-256")
						signer.SignDetached(pks, chain, Nothing, Nothing, Nothing, 0, PdfSigner.CryptoStandard.CMS)
					End Using
				End Using
			End Using
			Console.WriteLine($"PDF digitally signed successfully: {dest}")
		Catch ex As Exception
			Console.WriteLine($"Error signing PDF: {ex.Message}")
		End Try
	End Sub
End Class
$vbLabelText   $csharpLabel

當將 數位簽名 應用於 PDF 文件時,IronPDF 提供了一種使用 X509 證書直接且有效的方法來完成此操作。 其 API 簡化了流程,使其易於集成到工作流中,而不會犧牲對簽名安全性的控制。 相比之下,iTextPDF 的文件簽名過程設置更複雜,但提供了其他定制選項。 開發人員擁有更精細的控制權,但在導航 iTextPDF 的簽名配置和證書處理時可能會面臨更高的學習曲線。

能夠在PDF上添加和個性化水印會极大地帮助机密信息、版权保护、品牌推广或任何涉及敏感信息的任务。

對 PDF 進行浮水印可能對於品牌、機密性和版權保護至關重要。 以下是 IronPDF 和 iTextPDF 如何將浮水印應用於 PDF 文檔。

IronPDF

using IronPdf;

// Stamps a Watermark onto a new or existing PDF
var renderer = new ChromePdfRenderer();

var pdf = renderer.RenderUrlAsPdf("https://www.nuget.org/packages/IronPdf");
pdf.ApplyWatermark("<h2 style='color:red'>SAMPLE</h2>", 30, IronPdf.Editing.VerticalAlignment.Middle, IronPdf.Editing.HorizontalAlignment.Center);
pdf.SaveAs(@"C:\Path\To\Watermarked.pdf");
using IronPdf;

// Stamps a Watermark onto a new or existing PDF
var renderer = new ChromePdfRenderer();

var pdf = renderer.RenderUrlAsPdf("https://www.nuget.org/packages/IronPdf");
pdf.ApplyWatermark("<h2 style='color:red'>SAMPLE</h2>", 30, IronPdf.Editing.VerticalAlignment.Middle, IronPdf.Editing.HorizontalAlignment.Center);
pdf.SaveAs(@"C:\Path\To\Watermarked.pdf");
Imports IronPdf

' Stamps a Watermark onto a new or existing PDF
Private renderer = New ChromePdfRenderer()

Private pdf = renderer.RenderUrlAsPdf("https://www.nuget.org/packages/IronPdf")
pdf.ApplyWatermark("<h2 style='color:red'>SAMPLE</h2>", 30, IronPdf.Editing.VerticalAlignment.Middle, IronPdf.Editing.HorizontalAlignment.Center)
pdf.SaveAs("C:\Path\To\Watermarked.pdf")
$vbLabelText   $csharpLabel

iTextPdf

using iText.IO.Font;
using iText.IO.Font.Constants;
using iText.Kernel.Colors;
using iText.Kernel.Font;
using iText.Kernel.Pdf;
using iText.Kernel.Pdf.Canvas;
using iText.Kernel.Pdf.Extgstate;
using iText.Layout;
using iText.Layout.Element;
using iText.Layout.Properties;

public class TransparentWatermark 
{
    public static readonly string DEST = "results/sandbox/stamper/transparent_watermark.pdf";
    public static readonly string SRC = "../../../resources/pdfs/hero.pdf";

    public static void Main(string[] args) 
    {
        FileInfo file = new FileInfo(DEST);
        file.Directory.Create();

        new TransparentWatermark().ManipulatePdf(DEST);
    }

    protected void ManipulatePdf(string dest) 
    {
        PdfDocument pdfDoc = new PdfDocument(new PdfReader(SRC), new PdfWriter(dest));
        PdfCanvas under = new PdfCanvas(pdfDoc.GetFirstPage().NewContentStreamBefore(), new PdfResources(), pdfDoc);
        PdfFont font = PdfFontFactory.CreateFont(FontProgramFactory.CreateFont(StandardFonts.HELVETICA));
        Paragraph paragraph = new Paragraph("This watermark is added UNDER the existing content")
                .SetFont(font)
                .SetFontSize(15);

        Canvas canvasWatermark1 = new Canvas(under, pdfDoc.GetDefaultPageSize())
                .ShowTextAligned(paragraph, 297, 550, 1, TextAlignment.CENTER, VerticalAlignment.TOP, 0);
        canvasWatermark1.Close();
        PdfCanvas over = new PdfCanvas(pdfDoc.GetFirstPage());
        over.SetFillColor(ColorConstants.BLACK);
        paragraph = new Paragraph("This watermark is added ON TOP OF the existing content")
                .SetFont(font)
                .SetFontSize(15);

        Canvas canvasWatermark2 = new Canvas(over, pdfDoc.GetDefaultPageSize())
                .ShowTextAligned(paragraph, 297, 500, 1, TextAlignment.CENTER, VerticalAlignment.TOP, 0);
        canvasWatermark2.Close();
        paragraph = new Paragraph("This TRANSPARENT watermark is added ON TOP OF the existing content")
                .SetFont(font)
                .SetFontSize(15);
        over.SaveState();

        PdfExtGState gs1 = new PdfExtGState();
        gs1.SetFillOpacity(0.5f);
        over.SetExtGState(gs1);
        Canvas canvasWatermark3 = new Canvas(over, pdfDoc.GetDefaultPageSize())
                .ShowTextAligned(paragraph, 297, 450, 1, TextAlignment.CENTER, VerticalAlignment.TOP, 0);
        canvasWatermark3.Close();
        over.RestoreState();

        pdfDoc.Close();
    }
}
using iText.IO.Font;
using iText.IO.Font.Constants;
using iText.Kernel.Colors;
using iText.Kernel.Font;
using iText.Kernel.Pdf;
using iText.Kernel.Pdf.Canvas;
using iText.Kernel.Pdf.Extgstate;
using iText.Layout;
using iText.Layout.Element;
using iText.Layout.Properties;

public class TransparentWatermark 
{
    public static readonly string DEST = "results/sandbox/stamper/transparent_watermark.pdf";
    public static readonly string SRC = "../../../resources/pdfs/hero.pdf";

    public static void Main(string[] args) 
    {
        FileInfo file = new FileInfo(DEST);
        file.Directory.Create();

        new TransparentWatermark().ManipulatePdf(DEST);
    }

    protected void ManipulatePdf(string dest) 
    {
        PdfDocument pdfDoc = new PdfDocument(new PdfReader(SRC), new PdfWriter(dest));
        PdfCanvas under = new PdfCanvas(pdfDoc.GetFirstPage().NewContentStreamBefore(), new PdfResources(), pdfDoc);
        PdfFont font = PdfFontFactory.CreateFont(FontProgramFactory.CreateFont(StandardFonts.HELVETICA));
        Paragraph paragraph = new Paragraph("This watermark is added UNDER the existing content")
                .SetFont(font)
                .SetFontSize(15);

        Canvas canvasWatermark1 = new Canvas(under, pdfDoc.GetDefaultPageSize())
                .ShowTextAligned(paragraph, 297, 550, 1, TextAlignment.CENTER, VerticalAlignment.TOP, 0);
        canvasWatermark1.Close();
        PdfCanvas over = new PdfCanvas(pdfDoc.GetFirstPage());
        over.SetFillColor(ColorConstants.BLACK);
        paragraph = new Paragraph("This watermark is added ON TOP OF the existing content")
                .SetFont(font)
                .SetFontSize(15);

        Canvas canvasWatermark2 = new Canvas(over, pdfDoc.GetDefaultPageSize())
                .ShowTextAligned(paragraph, 297, 500, 1, TextAlignment.CENTER, VerticalAlignment.TOP, 0);
        canvasWatermark2.Close();
        paragraph = new Paragraph("This TRANSPARENT watermark is added ON TOP OF the existing content")
                .SetFont(font)
                .SetFontSize(15);
        over.SaveState();

        PdfExtGState gs1 = new PdfExtGState();
        gs1.SetFillOpacity(0.5f);
        over.SetExtGState(gs1);
        Canvas canvasWatermark3 = new Canvas(over, pdfDoc.GetDefaultPageSize())
                .ShowTextAligned(paragraph, 297, 450, 1, TextAlignment.CENTER, VerticalAlignment.TOP, 0);
        canvasWatermark3.Close();
        over.RestoreState();

        pdfDoc.Close();
    }
}
Imports iText.IO.Font
Imports iText.IO.Font.Constants
Imports iText.Kernel.Colors
Imports iText.Kernel.Font
Imports iText.Kernel.Pdf
Imports iText.Kernel.Pdf.Canvas
Imports iText.Kernel.Pdf.Extgstate
Imports iText.Layout
Imports iText.Layout.Element
Imports iText.Layout.Properties

Public Class TransparentWatermark
	Public Shared ReadOnly DEST As String = "results/sandbox/stamper/transparent_watermark.pdf"
	Public Shared ReadOnly SRC As String = "../../../resources/pdfs/hero.pdf"

	Public Shared Sub Main(ByVal args() As String)
		Dim file As New FileInfo(DEST)
		file.Directory.Create()

		Call (New TransparentWatermark()).ManipulatePdf(DEST)
	End Sub

	Protected Sub ManipulatePdf(ByVal dest As String)
		Dim pdfDoc As New PdfDocument(New PdfReader(SRC), New PdfWriter(dest))
		Dim under As New PdfCanvas(pdfDoc.GetFirstPage().NewContentStreamBefore(), New PdfResources(), pdfDoc)
		Dim font As PdfFont = PdfFontFactory.CreateFont(FontProgramFactory.CreateFont(StandardFonts.HELVETICA))
		Dim paragraph As Paragraph = (New Paragraph("This watermark is added UNDER the existing content")).SetFont(font).SetFontSize(15)

		Dim canvasWatermark1 As Canvas = (New Canvas(under, pdfDoc.GetDefaultPageSize())).ShowTextAligned(paragraph, 297, 550, 1, TextAlignment.CENTER, VerticalAlignment.TOP, 0)
		canvasWatermark1.Close()
		Dim over As New PdfCanvas(pdfDoc.GetFirstPage())
		over.SetFillColor(ColorConstants.BLACK)
		paragraph = (New Paragraph("This watermark is added ON TOP OF the existing content")).SetFont(font).SetFontSize(15)

		Dim canvasWatermark2 As Canvas = (New Canvas(over, pdfDoc.GetDefaultPageSize())).ShowTextAligned(paragraph, 297, 500, 1, TextAlignment.CENTER, VerticalAlignment.TOP, 0)
		canvasWatermark2.Close()
		paragraph = (New Paragraph("This TRANSPARENT watermark is added ON TOP OF the existing content")).SetFont(font).SetFontSize(15)
		over.SaveState()

		Dim gs1 As New PdfExtGState()
		gs1.SetFillOpacity(0.5F)
		over.SetExtGState(gs1)
		Dim canvasWatermark3 As Canvas = (New Canvas(over, pdfDoc.GetDefaultPageSize())).ShowTextAligned(paragraph, 297, 450, 1, TextAlignment.CENTER, VerticalAlignment.TOP, 0)
		canvasWatermark3.Close()
		over.RestoreState()

		pdfDoc.Close()
	End Sub
End Class
$vbLabelText   $csharpLabel

IronPDF 的 API 允許快速且直觀的 浮水印應用,靈活地使用 HTML 和 CSS 進行自定義。 這種方法對用戶友好,使得創建視覺上獨特的浮水印更容易,無需大量的設置。iTextPDF,則通過其更詳細的配置選項,允許高度自定義的浮水印位置,但需要更多的代碼工作。

有時PDF頁面需要在PDF上加印文字或圖片,類似於需要將水印應用於它們的PDF文件。

在 PDF 文件上蓋章內容與應用浮水印類似,但更專注於添加特定元素,如圖像或文本,用於標籤或品牌目的。 以下是 IronPDF 和 iTextPDF 如何執行此任務。

IronPDF

using IronPdf;
using IronPdf.Editing;

ChromePdfRenderer renderer = new ChromePdfRenderer();

PdfDocument pdf = renderer.RenderHtmlAsPdf("<h1>Example HTML Document!</h1>");

// Create text stamper
TextStamper textStamper = new TextStamper()
{
    Text = "Text Stamper!",
    FontFamily = "Bungee Spice",
    UseGoogleFont = true,
    FontSize = 30,
    IsBold = true,
    IsItalic = true,
    VerticalAlignment = VerticalAlignment.Top,
};

// Stamp the text stamper
pdf.ApplyStamp(textStamper);
pdf.SaveAs("stampText.pdf");

// Create image stamper
ImageStamper imageStamper = new ImageStamper(new Uri("https://ironpdf.com/img/svgs/iron-pdf-logo.svg"))
{
    VerticalAlignment = VerticalAlignment.Top,
};

// Stamp the image stamper
pdf.ApplyStamp(imageStamper, 0);
pdf.SaveAs("stampImage.pdf");
using IronPdf;
using IronPdf.Editing;

ChromePdfRenderer renderer = new ChromePdfRenderer();

PdfDocument pdf = renderer.RenderHtmlAsPdf("<h1>Example HTML Document!</h1>");

// Create text stamper
TextStamper textStamper = new TextStamper()
{
    Text = "Text Stamper!",
    FontFamily = "Bungee Spice",
    UseGoogleFont = true,
    FontSize = 30,
    IsBold = true,
    IsItalic = true,
    VerticalAlignment = VerticalAlignment.Top,
};

// Stamp the text stamper
pdf.ApplyStamp(textStamper);
pdf.SaveAs("stampText.pdf");

// Create image stamper
ImageStamper imageStamper = new ImageStamper(new Uri("https://ironpdf.com/img/svgs/iron-pdf-logo.svg"))
{
    VerticalAlignment = VerticalAlignment.Top,
};

// Stamp the image stamper
pdf.ApplyStamp(imageStamper, 0);
pdf.SaveAs("stampImage.pdf");
Imports IronPdf
Imports IronPdf.Editing

Private renderer As New ChromePdfRenderer()

Private pdf As PdfDocument = renderer.RenderHtmlAsPdf("<h1>Example HTML Document!</h1>")

' Create text stamper
Private textStamper As New TextStamper() With {
	.Text = "Text Stamper!",
	.FontFamily = "Bungee Spice",
	.UseGoogleFont = True,
	.FontSize = 30,
	.IsBold = True,
	.IsItalic = True,
	.VerticalAlignment = VerticalAlignment.Top
}

' Stamp the text stamper
pdf.ApplyStamp(textStamper)
pdf.SaveAs("stampText.pdf")

' Create image stamper
Dim imageStamper As New ImageStamper(New Uri("https://ironpdf.com/img/svgs/iron-pdf-logo.svg")) With {.VerticalAlignment = VerticalAlignment.Top}

' Stamp the image stamper
pdf.ApplyStamp(imageStamper, 0)
pdf.SaveAs("stampImage.pdf")
$vbLabelText   $csharpLabel

iTextPdf

using iText.Kernel.Pdf;
using iText.Layout;
using iText.Layout.Element;

public void StampPDF(string inputPdfPath, string outputPdfPath, string stampText)
{
    PdfDocument pdfDoc = new PdfDocument(new PdfReader(inputPdfPath), new PdfWriter(outputPdfPath));

    Document doc = new Document(pdfDoc);

    // Add stamp (text) to each page
    int numPages = pdfDoc.GetNumberOfPages();
    for (int i = 1; i <= numPages; i++)
    {
        doc.ShowTextAligned(new Paragraph(stampText),
                            36, 36, i, iText.Layout.Properties.TextAlignment.LEFT,
                            iText.Layout.Properties.VerticalAlignment.TOP, 0);
    }

    doc.Close();
}
using iText.Kernel.Pdf;
using iText.Layout;
using iText.Layout.Element;

public void StampPDF(string inputPdfPath, string outputPdfPath, string stampText)
{
    PdfDocument pdfDoc = new PdfDocument(new PdfReader(inputPdfPath), new PdfWriter(outputPdfPath));

    Document doc = new Document(pdfDoc);

    // Add stamp (text) to each page
    int numPages = pdfDoc.GetNumberOfPages();
    for (int i = 1; i <= numPages; i++)
    {
        doc.ShowTextAligned(new Paragraph(stampText),
                            36, 36, i, iText.Layout.Properties.TextAlignment.LEFT,
                            iText.Layout.Properties.VerticalAlignment.TOP, 0);
    }

    doc.Close();
}
Imports iText.Kernel.Pdf
Imports iText.Layout
Imports iText.Layout.Element

Public Sub StampPDF(ByVal inputPdfPath As String, ByVal outputPdfPath As String, ByVal stampText As String)
	Dim pdfDoc As New PdfDocument(New PdfReader(inputPdfPath), New PdfWriter(outputPdfPath))

	Dim doc As New Document(pdfDoc)

	' Add stamp (text) to each page
	Dim numPages As Integer = pdfDoc.GetNumberOfPages()
	For i As Integer = 1 To numPages
		doc.ShowTextAligned(New Paragraph(stampText), 36, 36, i, iText.Layout.Properties.TextAlignment.LEFT, iText.Layout.Properties.VerticalAlignment.TOP, 0)
	Next i

	doc.Close()
End Sub
$vbLabelText   $csharpLabel

IronPDF 的 圖像和文本蓋章 方法已經精簡且多功能,使開發人員輕鬆地將品牌內容或標籤添加到 PDF 頁面。 此 API 利用了熟悉的 HTML/CSS 樣式元素,使自定義變得直觀。 iTextPDF 也提供圖像和文本蓋章功能,雖然其配置需要更多的手動設置和 PDF 布局結構的工作知識。 直接在 PDF 頁面操控和樣式化內容的能力為開發人員提供了強大的蓋章工具,儘管 iTextPDF 的設置可能需要更多的努力。

有時,你可能需要將PDF從一種格式轉換到另一種格式。

在某些項目中,將 DOCX 文件轉換為 PDF 格式是必需的。 以下是 IronPDF 和 iText 處理此任務的比較,並突出了它們的不同點。

IronPDF

using IronPdf;

// Instantiate Renderer
DocxToPdfRenderer renderer = new DocxToPdfRenderer();

// Render from DOCX file
PdfDocument pdf = renderer.RenderDocxAsPdf("Modern-chronological-resume.docx");

// Save the PDF
pdf.SaveAs("pdfFromDocx.pdf");
using IronPdf;

// Instantiate Renderer
DocxToPdfRenderer renderer = new DocxToPdfRenderer();

// Render from DOCX file
PdfDocument pdf = renderer.RenderDocxAsPdf("Modern-chronological-resume.docx");

// Save the PDF
pdf.SaveAs("pdfFromDocx.pdf");
Imports IronPdf

' Instantiate Renderer
Private renderer As New DocxToPdfRenderer()

' Render from DOCX file
Private pdf As PdfDocument = renderer.RenderDocxAsPdf("Modern-chronological-resume.docx")

' Save the PDF
pdf.SaveAs("pdfFromDocx.pdf")
$vbLabelText   $csharpLabel

iTextPDF

與 IronPDF 不同,iTextPDF 不具有將 DOCX 轉換為 PDF 的內置支持。 為了執行這種轉換,開發人員必須依賴第三方庫,如 DocX 或 Aspose.Words,先將 DOCX 文件轉換為 PDF 兼容格式,然後可以使用 iTextPDF 處理或修改該文件。

IronPDF 提供了一個直接的、內置的 DOCX 到 PDF 的轉換 解決方案,消除了對於其他庫的需求。 這使得其對於需要快速且集成方法的開發人員來說非常合適。 相比之下,iTextPDF 依賴於外部庫來轉換 DOCX 文件,這需要額外的設置和依賴關係,可能增加項目的複雜性。

Bootstrap 和現代 CSS 框架支持

當從 Bootstrap 樣式的 Web 應用程序生成 PDF 時,完整框架支持可以確保設計一致性,而無需平行的 CSS 文件或佈局修改。

IronPDF:完整的 Bootstrap 框架支持

IronPDF 的 Chromium 引擎提供完整支持:

  • Bootstrap 5:完整的 flexbox 佈局、CSS Grid、實用程序類別、所有組件
  • Bootstrap 4:完整的卡片系統、導航、flex 實用工具、響應設計
  • Tailwind CSS:所有实用类,具有浏览器准确的渲染
  • Foundation: 完整的網格系統和組件庫
  • 现代 CSS3:Flexbox、CSS Grid、自定义属性、动画、过渡

Real-world validation: IronPDF renders the Bootstrap homepage and all official examples with pixel-perfect accuracy.

iTextPDF:有限的 Bootstrap 支持

iTextPDF 使用 pdfHTML,選擇性地支持 CSS3:

  • 有限的 flexbox 支持:在 7.1.15 版中增加了但不完整
  • 不支持 CSS Grid:基於 Grid 的 Bootstrap 佈局不支持
  • Bootstrap 3 限制:現代的 Bootstrap 4/5 組件需要解決方案
  • 手動佈局轉換:複雜佈局通常需要特定於 PDF 的代碼

iTextPDF 的文檔明確表示,可能無法渲染高級 CSS 特性,需要開發人員測試每個 Bootstrap 組件,並經常創建簡化的佈局。

開發影響:團隊必須維護單獨的佈局代碼以進行 PDF 生成,或廣泛地測試和修改 Bootstrap 組件,這會增加開發時間並減少設計一致性。

有关完整的 Bootstrap 框架指南和 CSS3 渲染能力,请参阅 Bootstrap & Flexbox CSS 指南。

代碼示例比較的摘要

IronPDF vs iTextPDF 比較圖片

有關更詳細的示例,請參閱 IronPDF 範例

定價和許可證:IronPDF vs. iTextPdf 庫

IronPDF定價和許可

IronPDF 有不同級別和附加功能的許可證購買。 開發人員還可以購買 Iron Suite,以兩個的價格獲得訪問所有 IronSoftware 的產品。 如果您尚未準備好購買許可證,IronPDF 提供 免費試用

  • 永久使用許可證: 提供一系列永久使用許可證,具體取決於您的團隊規模、專案需求和地點數量。 每種授權類型都包含郵件支持。
  • Lite 許可證:此許可證的費用為 $799,並支持一名開發者、一個地點和一個項目。
  • Plus 許可證: 支持三位開發者、三個地點和三個專案,這一步是繼 Lite 許可證之後的升級,費用是 $1,199。 加強授權提供即時聊天支持和電話支持,除此之外還擁有基本的郵件支持。
  • Professional 許可證:此許可證適合較大的團隊,支持十位開發者、十個地點和十個專案,費用為 $2,399。 除前一級別的聯絡支持頻道,同時提供屏幕共享支持。
  • 免版稅再分發: IronPDF 的許可證還提供免版稅再分發保障,額外費用為 $2,399。
  • 不中斷的產品支持:IronPDF 提供持續的產品更新、安全功能升級以及其工程團隊的支持,價格為 999 美元/年,或一次性購買 1,999 美元的 5 年保障。
  • Iron Suite:支付 $1,498,即可獲得包括 IronPDF, IronOCR, IronWord, IronXL, IronBarcode, IronQR, IronZIP, IronPrint 和 IronWebScraper 在內的所有 Iron Software 產品。

IronPDF vs iTextPDF 定價圖片

iTextPDF 許可證

  • AGPL 許可證:iTextPDF Core 庫在 AGPL 許可證下是開源的,可以免費使用但有條件。 開發人員必須釋放任何修改以相同的許可證。
  • 商業許可證:對於不符合 AGPL 條件的開發商,iTextPDF 提供通過報價模式的商業許可證。

文件和支持:IronPDF vs. iTextPdf

IronPDF

  • 全面的文件:涵蓋其所有特徵的廣泛和用戶友好的文件。
  • 24/5 支持:提供活躍的工程師支持。
  • 視頻教程:在 YouTube 上提供步驟分解的視頻指南。
  • 社區論壇:活躍社區提供額外支持。
  • 定期更新:每月的產品更新,確保最新的功能和安全修復。

iTextPDF

iTextPDF 為其廣泛的功能集提供了強大的文檔和支持。

  • 文檔:iText PDF 文檔詳細涵蓋了可用的功能。
  • 範例和教程:代碼範例和教程幫助開發人員入門。
  • GitHub 社區:開發人員可以報告問題、提交請求和與 iTextPDF 團隊互動。
  • 定期更新:iTextPDF 提供頻繁的更新和改進。

For more details on IronPDF documentation and support, visit the IronPDF Documentation and the IronSoftware YouTube Channel.

結論

在 .NET 的 PDF 操作工具領域,IronPDF 和 iTextPDF 都為開發人員提供了強大的解決方案。 IronPDF 以其在 .NET 平台上的簡單集成和用戶友好特性如無外部依賴的 DOCX 到 PDF 轉換而脫穎而出。 相比之下,以靈活性和豐富的功能集而著稱的 iTextPDF 仍然是一個強大的選擇,尤其是在與其他工具結合使用時,儘管 DOCX 轉換需要額外的依賴。

最終,在 IronPDF 和 iTextPDF 之間的選擇將取決於您的項目的具體需求、許可證偏好和所需的支持水平。 這兩個庫都為 .NET 應用程序中的 PDF 工作流程提供了可靠的精簡方法。

請注意iTextPDF 是其各自所有者的註冊商標。 本網站與 iTextPDF 無關、未獲得其認可或贊助。 所有產品名稱、徽標和品牌均為其各自所有者的財產。 比較僅供信息參考,並反映撰寫時公開可用的信息。

常見問題解答

怎樣在 C# 中將 HTML 轉換為 PDF?

您可以使用 IronPDF 的 RenderHtmlAsPdf 方法將 HTML 字符串轉換為 PDF。您還可以使用 RenderHtmlFileAsPdf 將 HTML 文件轉換為 PDF。

IronPDF 提供哪些 PDF 創建和操作功能?

IronPDF 提供了 HTML 到 PDF 轉換、PDF 合併、加密、數位簽名、水印和 DOCX 到 PDF 轉換等功能。

IronPDF 如何簡化 PDF 簽名?

IronPDF 允許您使用 X509 證書對 PDF 文件進行數位簽名,提供了一種安全文件的簡單方法。

IronPDF 可以用於不同的操作系統嗎?

是的,IronPDF 支持跨平台兼容。它可以無縫運行在 Windows、Linux 和 Mac 上,並且與 .NET Core、.NET Standard 和 .NET Framework 兼容。

iTextPDF 在文件加密方面與 IronPDF 有何不同?

iTextPDF 提供詳細的加密標準設置,而 IronPDF 則通過內建的易於實施的加密方法簡化了這一過程。

IronPDF 用戶有哪些支援資源可用?

IronPDF 提供廣泛的支持,包括全面的文檔、視頻教程、社區論壇和24/5工程師支持。

IronPDF 如何處理 DOCX 到 PDF 的轉換?

IronPDF 包含本地的 DOCX 到 PDF 轉換功能,允許無需額外庫即可無縫集成。

IronPDF 的許可選擇有哪些?

IronPDF 提供無期限許可證,多個等級例如 Lite、Plus 和 Professional,並提供免版稅再分發和持續產品支持的選項。

如何使用 IronPDF 向 PDF 應用水印?

IronPDF 允許您輕鬆使用 HTML 和 CSS 應用水印,使您能夠快速添加文本或圖像水印,並根據需要進行自訂。

什麼讓 IronPDF 適合從事 .NET 應用開發的開發者?

IronPDF 設計為用戶友好,具有簡化的 API,使其在 HTML 到 PDF 轉換、加密和數位簽名等任務中更高效,適合 .NET 開發者。

Curtis Chau
技術作家

Curtis Chau 擁有卡爾頓大學計算機科學學士學位,專注於前端開發,擅長於 Node.js、TypeScript、JavaScript 和 React。Curtis 熱衷於創建直觀且美觀的用戶界面,喜歡使用現代框架並打造結構良好、視覺吸引人的手冊。

除了開發之外,Curtis 對物聯網 (IoT) 有著濃厚的興趣,探索將硬體和軟體結合的創新方式。在閒暇時間,他喜愛遊戲並構建 Discord 機器人,結合科技與創意的樂趣。