如何在 PDF 上畫文字和位圖
Apache PDFBox是一個備受尊敬的開源Java程式庫,用於處理PDF。 然而,對於.NET開發者來說,現有的選擇是非官方的社群驅動移植,這帶來了重大挑戰—Java風格的API、不完整的功能覆蓋以及有限的.NET社群支援。 本指南提供了從Apache PDFBox .NET移植到IronPDF的詳細遷移路徑,這是一個專為.NET生態系統構建的原生.NET PDF程式庫。
為什麼考慮從Apache PDFBox .NET移植遷移?
雖然Apache PDFBox在Java生態系統中表現傑出,但其非官方的.NET移植存在多種挑戰,影響.NET開發團隊的工作。
非官方移植狀態
Apache PDFBox主要是Java程式庫(當前版本3.0.7,遺留版本2.0.36,Apache License 2.0)。 所有.NET選項都是社群驅動的移植,其中大多數已被遺棄:Pdfbox 1.1.1(最後發布於2013年,基於PDFBox 1.8.2構建),Pdfbox-IKVM 1.8.9(最後發布於2017年3月),PdfBox_DotNet_Version 2.0.15(最後發布於2019年7月)。 唯一積極維護的選項是MASES.NetPDF(3.0.x版本,跟踪PDFBox 3.0.x),這是一個JCOBridge包裝,需要在運行時與CLR一起使用JVM。 這些移植通常落後於Java的版本,可能缺少關鍵功能、錯誤修復或安全更新—這是值得權衡的長期.NET專案風險。
Java首選API設計
移植的API保留了Java慣例,這在.NET程式碼中顯得不熟悉。 開發者會遇到PascalCase,Java IDisposable模式。 這種認知開銷影響開發速度和程式碼的可維護性。
不支援HTML渲染功能
Apache PDFBox的設計是為了進行PDF操作,不是HTML到PDF轉換。 建立PDF需要手動構建頁面並進行精確的座標定位—這是一個乏味且易出錯的過程,無法適應現代文件生成的需求。
有限的.NET社群支援
圍繞Apache PDFBox移植的.NET生態系統非常稀少。 相比於擁有活躍.NET社群的程式庫,尋求針對.NET特定問題的幫助、範例或最佳實踐顯得困難。
JVM相依性
基於IKVM的移植(Pdfbox-IKVM, Pdfbox)捆綁了一個.NET JVM的重新實現,而MASES.NetPDF通過JCOBridge調用一個真正的JVM。 無論哪種方式,部署都攜帶Java運行時包袱,這是典型的.NET程式庫所避免的。
Apache PDFBox vs. IronPDF: 主要差異
了解這些程式庫之間的基本差異,有助於制定有效的遷移策略。
| 方面 | Apache PDFBox .NET移植 | IronPDF |
|---|---|---|
| 原生設計 | 以Java為中心,非官方.NET移植 | 原生.NET程式庫 |
| API風格 | Java慣例(camelCase, close()) |
典型的C#(PascalCase, using) |
| HTML渲染 | 不支援(手動頁面構建) | 完整的基於Chromium的HTML/CSS/JS |
| PDF建立 | 手動坐標定位 | 基於 CSS 的佈局 |
| 社群 | 以Java為中心,稀少的.NET資源 | 活躍的.NET社群 |
| 支援 | 僅限社群支援 | 提供商業支援 |
| 資源清理 | 顯式close()調用 |
IDiposable與using語句 |
遷移前準備
前提條件
確保您的環境符合以下要求:
- .NET Framework 4.6.2+ or .NET Core 3.1 / .NET 5-9
- Visual Studio 2019+ or JetBrains Rider
- NuGet包管理器存取 -IronPDF許可證金鑰(免費試用可在 ironpdf.com 獲得)
審核Apache PDFBox使用情況
在您的解決方案目錄中運行這些命令,以識別所有Apache PDFBox引用:
grep -r "org.apache.pdfbox\|Org.Apache.Pdfbox\|PDDocument\|PDFTextStripper" --include="*.cs" .
grep -rE "Pdfbox|Pdfbox-IKVM|PdfBox_DotNet_Version|MASES\.NetPDF" --include="*.csproj" .
grep -r "org.apache.pdfbox\|Org.Apache.Pdfbox\|PDDocument\|PDFTextStripper" --include="*.cs" .
grep -rE "Pdfbox|Pdfbox-IKVM|PdfBox_DotNet_Version|MASES\.NetPDF" --include="*.csproj" .
預期的中斷變更
| 類別 | Apache PDFBox .NET移植 | IronPDF | 遷移動作 |
|---|---|---|---|
| 物件模型 | PDDocument, PDPage |
PdfDocument, ChromePdfRenderer |
不同的類層次結構 |
| PDF建立 | 手動頁面/內容流 | HTML渲染 | 重寫建立邏輯 |
| 方法風格 | camelCase()(Java風格) |
PascalCase()(.NET風格) |
更新方法名稱 |
| 資源清理 | document.close() |
using語句 |
更換處理模式 |
| 文件存取 | Java File物件 |
標準.NET字串/流 | 使用.NET型別 |
| 文字提取 | PDFTextStripper類 |
pdf.ExtractAllText() |
更簡單的API |
逐步遷移過程
步驟1:更新NuGet包
移除Apache PDFBox .NET移植包並安裝IronPDF:
# Remove whichever PDFBox .NET port your project uses
dotnet remove package Pdfbox # built against PDFBox 1.8.2 (2013)
dotnet remove package Pdfbox-IKVM # IKVM wrapper, last update 2017
dotnet remove package PdfBox_DotNet_Version # last update 2019
dotnet remove package MASES.NetPDF # JCOBridge wrapper, requires JVM
# Install IronPDF
dotnet add package IronPdf
# Remove whichever PDFBox .NET port your project uses
dotnet remove package Pdfbox # built against PDFBox 1.8.2 (2013)
dotnet remove package Pdfbox-IKVM # IKVM wrapper, last update 2017
dotnet remove package PdfBox_DotNet_Version # last update 2019
dotnet remove package MASES.NetPDF # JCOBridge wrapper, requires JVM
# Install IronPDF
dotnet add package IronPdf
步驟 2:配置許可證金鑰
在應用程式啟動時新增IronPDF授權金鑰:
// Add at application startup, before anyIronPDFoperations
IronPdf.License.LicenseKey = "YOUR-LICENSE-KEY";
// Add at application startup, before anyIronPDFoperations
IronPdf.License.LicenseKey = "YOUR-LICENSE-KEY";
' Add at application startup, before any IronPDF operations
IronPdf.License.LicenseKey = "YOUR-LICENSE-KEY"
步驟 3:更新命名空間參考
在您的解決方案中執行全域查找和替換:
所有PDFBox .NET移植都影射了Java包層次結構。 基於IKVM的移植保留了Java的小寫形式(org.apache.pdfbox.*); Org.Apache.Pdfbox.*)。
| 查找 | 替換為 |
|---|---|
using org.apache.pdfbox.pdmodel;(IKVM移植) |
using IronPdf; |
using org.apache.pdfbox.text;(IKVM移植) |
using IronPdf; |
using org.apache.pdfbox.multipdf;(IKVM移植) |
using IronPdf; |
using Org.Apache.Pdfbox.Pdmodel;(MASES.NetPDF) |
using IronPdf; |
using Org.Apache.Pdfbox.Text;(MASES.NetPDF) |
using IronPdf; |
完整 API 遷移參考
文件操作
| Apache PDFBox方法 | IronPDF方法 |
|---|---|
PDDocument.load(path) |
PdfDocument.FromFile(path) |
PDDocument.load(stream) |
PdfDocument.FromStream(stream) |
new PDDocument() |
new ChromePdfRenderer() |
document.save(path) |
pdf.SaveAs(path) |
document.close() |
Dispose() |
document.getNumberOfPages() |
pdf.PageCount |
document.getPage(index) |
pdf.Pages[index] |
document.removePage(index) |
pdf.RemovePages(index) |
文字提取
| Apache PDFBox方法 | IronPDF方法 |
|---|---|
new PDFTextStripper() |
不需要 |
stripper.getText(document) |
pdf.ExtractAllText() |
stripper.setStartPage(n) |
pdf.Pages[n].Text |
stripper.setSortByPosition(true) |
自動 |
合併和分割操作
| Apache PDFBox方法 | IronPDF方法 |
|---|---|
new PDFMergerUtility() |
不需要 |
merger.addSource(file) |
使用FromFile()載入 |
merger.mergeDocuments() |
PdfDocument.Merge(pdfs) |
new Splitter() |
不需要 |
splitter.split(document) |
pdf.CopyPages(indices) |
安全和加密
| Apache PDFBox方法 | IronPDF方法 |
|---|---|
StandardProtectionPolicy |
pdf.SecuritySettings |
policy.setUserPassword() |
pdf.SecuritySettings.UserPassword |
policy.setOwnerPassword() |
pdf.SecuritySettings.OwnerPassword |
policy.setPermissions() |
pdf.SecuritySettings.AllowUserXxx |
程式碼遷移範例
文字提取
最常見的Apache PDFBox操作演示了IronPDF提供的API簡化。
Apache PDFBox .NET移植實施:
// Apache PDFBox is a Java library — there is no official .NET port.
// Example uses Pdfbox-IKVM (last published 2017) on NuGet; namespaces
// mirror the Java packages exactly because IKVM exposes the Java API.
using org.apache.pdfbox.pdmodel;
using org.apache.pdfbox.text;
using java.io;
using System;
class Program
{
static void Main()
{
PDDocument document = PDDocument.load(new File("document.pdf"));
try
{
PDFTextStripper stripper = new PDFTextStripper();
string text = stripper.getText(document);
Console.WriteLine(text);
}
finally
{
document.close();
}
}
}
// Apache PDFBox is a Java library — there is no official .NET port.
// Example uses Pdfbox-IKVM (last published 2017) on NuGet; namespaces
// mirror the Java packages exactly because IKVM exposes the Java API.
using org.apache.pdfbox.pdmodel;
using org.apache.pdfbox.text;
using java.io;
using System;
class Program
{
static void Main()
{
PDDocument document = PDDocument.load(new File("document.pdf"));
try
{
PDFTextStripper stripper = new PDFTextStripper();
string text = stripper.getText(document);
Console.WriteLine(text);
}
finally
{
document.close();
}
}
}
Imports org.apache.pdfbox.pdmodel
Imports org.apache.pdfbox.text
Imports java.io
Imports System
Module Program
Sub Main()
Dim document As PDDocument = PDDocument.load(New File("document.pdf"))
Try
Dim stripper As New PDFTextStripper()
Dim text As String = stripper.getText(document)
Console.WriteLine(text)
Finally
document.close()
End Try
End Sub
End Module
IronPDF實現:
// NuGet: Install-Package IronPdf
using IronPdf;
using System;
class Program
{
static void Main()
{
var pdf = PdfDocument.FromFile("document.pdf");
string text = pdf.ExtractAllText();
Console.WriteLine(text);
// Or extract text from specific pages
string pageText = pdf.ExtractTextFromPage(0);
Console.WriteLine(pageText);
}
}
// NuGet: Install-Package IronPdf
using IronPdf;
using System;
class Program
{
static void Main()
{
var pdf = PdfDocument.FromFile("document.pdf");
string text = pdf.ExtractAllText();
Console.WriteLine(text);
// Or extract text from specific pages
string pageText = pdf.ExtractTextFromPage(0);
Console.WriteLine(pageText);
}
}
Imports IronPdf
Imports System
Class Program
Shared Sub Main()
Dim pdf = PdfDocument.FromFile("document.pdf")
Dim text As String = pdf.ExtractAllText()
Console.WriteLine(text)
' Or extract text from specific pages
Dim pageText As String = pdf.ExtractTextFromPage(0)
Console.WriteLine(pageText)
End Sub
End Class
IronPDF完全消除了PDFTextStripper類,將多步提取替換為單一方法調用。
HTML到PDF轉換
Apache PDFBox本身不支援HTML到PDF轉換—這代表著一個基本的能力差距。
IronPDF實現:
// NuGet: Install-Package IronPdf
using IronPdf;
using System;
class Program
{
static void Main()
{
var renderer = new ChromePdfRenderer();
var pdf = renderer.RenderHtmlAsPdf("<h1>Hello World</h1><p>This is HTML to PDF</p>");
pdf.SaveAs("output.pdf");
Console.WriteLine("PDF created successfully");
}
}
// NuGet: Install-Package IronPdf
using IronPdf;
using System;
class Program
{
static void Main()
{
var renderer = new ChromePdfRenderer();
var pdf = renderer.RenderHtmlAsPdf("<h1>Hello World</h1><p>This is HTML to PDF</p>");
pdf.SaveAs("output.pdf");
Console.WriteLine("PDF created successfully");
}
}
Imports IronPdf
Imports System
Class Program
Shared Sub Main()
Dim renderer = New ChromePdfRenderer()
Dim pdf = renderer.RenderHtmlAsPdf("<h1>Hello World</h1><p>This is HTML to PDF</p>")
pdf.SaveAs("output.pdf")
Console.WriteLine("PDF created successfully")
End Sub
End Class
IronPDF的基於Chromium的渲染引擎提供了完整的HTML、CSS和JavaScript支援。 對於高級場景,請參見HTML 到 PDF 文件。
合併多個 PDF
Apache PDFBox .NET移植實施:
// Apache PDFBox via a .NET port (e.g. Pdfbox-IKVM on nuget.org).
// The Java class org.apache.pdfbox.multipdf.PDFMergerUtility is exposed
// directly through IKVM, so method names stay Java-style (camelCase).
using org.apache.pdfbox.multipdf;
using org.apache.pdfbox.io;
using System;
class Program
{
static void Main()
{
PDFMergerUtility merger = new PDFMergerUtility();
merger.addSource("document1.pdf");
merger.addSource("document2.pdf");
merger.setDestinationFileName("merged.pdf");
// MemoryUsageSetting governs heap vs temp-file buffering
merger.mergeDocuments(MemoryUsageSetting.setupMainMemoryOnly());
Console.WriteLine("PDFs merged");
}
}
// Apache PDFBox via a .NET port (e.g. Pdfbox-IKVM on nuget.org).
// The Java class org.apache.pdfbox.multipdf.PDFMergerUtility is exposed
// directly through IKVM, so method names stay Java-style (camelCase).
using org.apache.pdfbox.multipdf;
using org.apache.pdfbox.io;
using System;
class Program
{
static void Main()
{
PDFMergerUtility merger = new PDFMergerUtility();
merger.addSource("document1.pdf");
merger.addSource("document2.pdf");
merger.setDestinationFileName("merged.pdf");
// MemoryUsageSetting governs heap vs temp-file buffering
merger.mergeDocuments(MemoryUsageSetting.setupMainMemoryOnly());
Console.WriteLine("PDFs merged");
}
}
Imports org.apache.pdfbox.multipdf
Imports org.apache.pdfbox.io
Imports System
Module Program
Sub Main()
Dim merger As New PDFMergerUtility()
merger.addSource("document1.pdf")
merger.addSource("document2.pdf")
merger.setDestinationFileName("merged.pdf")
' MemoryUsageSetting governs heap vs temp-file buffering
merger.mergeDocuments(MemoryUsageSetting.setupMainMemoryOnly())
Console.WriteLine("PDFs merged")
End Sub
End Module
IronPDF實現:
// NuGet: Install-Package IronPdf
using IronPdf;
using System;
using System.Collections.Generic;
class Program
{
static void Main()
{
var pdf1 = PdfDocument.FromFile("document1.pdf");
var pdf2 = PdfDocument.FromFile("document2.pdf");
var pdf3 = PdfDocument.FromFile("document3.pdf");
var merged = PdfDocument.Merge(pdf1, pdf2, pdf3);
merged.SaveAs("merged.pdf");
Console.WriteLine("PDFs merged successfully");
}
}
// NuGet: Install-Package IronPdf
using IronPdf;
using System;
using System.Collections.Generic;
class Program
{
static void Main()
{
var pdf1 = PdfDocument.FromFile("document1.pdf");
var pdf2 = PdfDocument.FromFile("document2.pdf");
var pdf3 = PdfDocument.FromFile("document3.pdf");
var merged = PdfDocument.Merge(pdf1, pdf2, pdf3);
merged.SaveAs("merged.pdf");
Console.WriteLine("PDFs merged successfully");
}
}
Imports IronPdf
Imports System
Imports System.Collections.Generic
Module Program
Sub Main()
Dim pdf1 = PdfDocument.FromFile("document1.pdf")
Dim pdf2 = PdfDocument.FromFile("document2.pdf")
Dim pdf3 = PdfDocument.FromFile("document3.pdf")
Dim merged = PdfDocument.Merge(pdf1, pdf2, pdf3)
merged.SaveAs("merged.pdf")
Console.WriteLine("PDFs merged successfully")
End Sub
End Module
IronPDF的靜態Merge方法直接接受多個文件,消除了實用類模式。
從頭開始建立PDF
在建立PDF時,最明顯的差異出現了。 Apache PDFBox需要手動坐標定位。
Apache PDFBox .NET移植實施:
using org.apache.pdfbox.pdmodel;
using org.apache.pdfbox.pdmodel.font;
using org.apache.pdfbox.pdmodel.edit;
public void CreatePdf(string outputPath)
{
PDDocument document = new PDDocument();
try
{
PDPage page = new PDPage();
document.addPage(page);
PDPageContentStream contentStream = new PDPageContentStream(document, page);
PDFont font = PDType1Font.HELVETICA_BOLD;
contentStream.beginText();
contentStream.setFont(font, 24);
contentStream.moveTextPositionByAmount(72, 700);
contentStream.drawString("Hello World");
contentStream.endText();
contentStream.beginText();
contentStream.setFont(PDType1Font.HELVETICA, 12);
contentStream.moveTextPositionByAmount(72, 650);
contentStream.drawString("This is a paragraph of text.");
contentStream.endText();
contentStream.close();
document.save(outputPath);
}
finally
{
document.close();
}
}
using org.apache.pdfbox.pdmodel;
using org.apache.pdfbox.pdmodel.font;
using org.apache.pdfbox.pdmodel.edit;
public void CreatePdf(string outputPath)
{
PDDocument document = new PDDocument();
try
{
PDPage page = new PDPage();
document.addPage(page);
PDPageContentStream contentStream = new PDPageContentStream(document, page);
PDFont font = PDType1Font.HELVETICA_BOLD;
contentStream.beginText();
contentStream.setFont(font, 24);
contentStream.moveTextPositionByAmount(72, 700);
contentStream.drawString("Hello World");
contentStream.endText();
contentStream.beginText();
contentStream.setFont(PDType1Font.HELVETICA, 12);
contentStream.moveTextPositionByAmount(72, 650);
contentStream.drawString("This is a paragraph of text.");
contentStream.endText();
contentStream.close();
document.save(outputPath);
}
finally
{
document.close();
}
}
Imports org.apache.pdfbox.pdmodel
Imports org.apache.pdfbox.pdmodel.font
Imports org.apache.pdfbox.pdmodel.edit
Public Sub CreatePdf(outputPath As String)
Dim document As New PDDocument()
Try
Dim page As New PDPage()
document.addPage(page)
Dim contentStream As New PDPageContentStream(document, page)
Dim font As PDFont = PDType1Font.HELVETICA_BOLD
contentStream.beginText()
contentStream.setFont(font, 24)
contentStream.moveTextPositionByAmount(72, 700)
contentStream.drawString("Hello World")
contentStream.endText()
contentStream.beginText()
contentStream.setFont(PDType1Font.HELVETICA, 12)
contentStream.moveTextPositionByAmount(72, 650)
contentStream.drawString("This is a paragraph of text.")
contentStream.endText()
contentStream.close()
document.save(outputPath)
Finally
document.close()
End Try
End Sub
IronPDF實現:
using IronPdf;
public void CreatePdf(string outputPath)
{
var renderer = new ChromePdfRenderer();
string html = @"
<html>
<head>
<style>
body { font-family: Helvetica, Arial, sans-serif; margin: 1in; }
h1 { font-size: 24pt; font-weight: bold; }
p { font-size: 12pt; }
</style>
</head>
<body>
<h1>Hello World</h1>
<p>This is a paragraph of text.</p>
</body>
</html>";
using var pdf = renderer.RenderHtmlAsPdf(html);
pdf.SaveAs(outputPath);
}
using IronPdf;
public void CreatePdf(string outputPath)
{
var renderer = new ChromePdfRenderer();
string html = @"
<html>
<head>
<style>
body { font-family: Helvetica, Arial, sans-serif; margin: 1in; }
h1 { font-size: 24pt; font-weight: bold; }
p { font-size: 12pt; }
</style>
</head>
<body>
<h1>Hello World</h1>
<p>This is a paragraph of text.</p>
</body>
</html>";
using var pdf = renderer.RenderHtmlAsPdf(html);
pdf.SaveAs(outputPath);
}
Imports IronPdf
Public Sub CreatePdf(outputPath As String)
Dim renderer As New ChromePdfRenderer()
Dim html As String = "
<html>
<head>
<style>
body { font-family: Helvetica, Arial, sans-serif; margin: 1in; }
h1 { font-size: 24pt; font-weight: bold; }
p { font-size: 12pt; }
</style>
</head>
<body>
<h1>Hello World</h1>
<p>This is a paragraph of text.</p>
</body>
</html>"
Using pdf = renderer.RenderHtmlAsPdf(html)
pdf.SaveAs(outputPath)
End Using
End Sub
基於HTML/CSS的建立消除了坐標計算、字體管理和內容流處理。
新增密碼保護
Apache PDFBox .NET移植實施:
using org.apache.pdfbox.pdmodel;
using org.apache.pdfbox.pdmodel.encryption;
public void ProtectPdf(string inputPath, string outputPath, string password)
{
PDDocument document = PDDocument.load(new File(inputPath));
try
{
AccessPermission ap = new AccessPermission();
ap.setCanPrint(true);
ap.setCanExtractContent(false);
StandardProtectionPolicy spp = new StandardProtectionPolicy(password, password, ap);
spp.setEncryptionKeyLength(128);
document.protect(spp);
document.save(outputPath);
}
finally
{
document.close();
}
}
using org.apache.pdfbox.pdmodel;
using org.apache.pdfbox.pdmodel.encryption;
public void ProtectPdf(string inputPath, string outputPath, string password)
{
PDDocument document = PDDocument.load(new File(inputPath));
try
{
AccessPermission ap = new AccessPermission();
ap.setCanPrint(true);
ap.setCanExtractContent(false);
StandardProtectionPolicy spp = new StandardProtectionPolicy(password, password, ap);
spp.setEncryptionKeyLength(128);
document.protect(spp);
document.save(outputPath);
}
finally
{
document.close();
}
}
Imports org.apache.pdfbox.pdmodel
Imports org.apache.pdfbox.pdmodel.encryption
Public Sub ProtectPdf(inputPath As String, outputPath As String, password As String)
Dim document As PDDocument = PDDocument.load(New File(inputPath))
Try
Dim ap As New AccessPermission()
ap.setCanPrint(True)
ap.setCanExtractContent(False)
Dim spp As New StandardProtectionPolicy(password, password, ap)
spp.setEncryptionKeyLength(128)
document.protect(spp)
document.save(outputPath)
Finally
document.close()
End Try
End Sub
IronPDF實現:
using IronPdf;
public void ProtectPdf(string inputPath, string outputPath, string password)
{
using var pdf = PdfDocument.FromFile(inputPath);
pdf.SecuritySettings.UserPassword = password;
pdf.SecuritySettings.OwnerPassword = password;
pdf.SecuritySettings.AllowUserPrinting = PdfPrintSecurity.FullPrintRights;
pdf.SecuritySettings.AllowUserCopyPasteContent = false;
pdf.SaveAs(outputPath);
}
using IronPdf;
public void ProtectPdf(string inputPath, string outputPath, string password)
{
using var pdf = PdfDocument.FromFile(inputPath);
pdf.SecuritySettings.UserPassword = password;
pdf.SecuritySettings.OwnerPassword = password;
pdf.SecuritySettings.AllowUserPrinting = PdfPrintSecurity.FullPrintRights;
pdf.SecuritySettings.AllowUserCopyPasteContent = false;
pdf.SaveAs(outputPath);
}
Imports IronPdf
Public Sub ProtectPdf(inputPath As String, outputPath As String, password As String)
Using pdf = PdfDocument.FromFile(inputPath)
pdf.SecuritySettings.UserPassword = password
pdf.SecuritySettings.OwnerPassword = password
pdf.SecuritySettings.AllowUserPrinting = PdfPrintSecurity.FullPrintRights
pdf.SecuritySettings.AllowUserCopyPasteContent = False
pdf.SaveAs(outputPath)
End Using
End Sub
IronPDF使用強型別的屬性,而不是單獨的許可和政策物件。
新增水印
Apache PDFBox .NET移植實施:
using org.apache.pdfbox.pdmodel;
using org.apache.pdfbox.pdmodel.edit;
using org.apache.pdfbox.pdmodel.font;
public void AddWatermark(string inputPath, string outputPath, string watermarkText)
{
PDDocument document = PDDocument.load(new File(inputPath));
try
{
PDFont font = PDType1Font.HELVETICA_BOLD;
for (int i = 0; i < document.getNumberOfPages(); i++)
{
PDPage page = document.getPage(i);
PDPageContentStream cs = new PDPageContentStream(
document, page, PDPageContentStream.AppendMode.APPEND, true, true);
cs.beginText();
cs.setFont(font, 72);
cs.setNonStrokingColor(200, 200, 200);
cs.setTextMatrix(Matrix.getRotateInstance(Math.toRadians(45), 200, 400));
cs.showText(watermarkText);
cs.endText();
cs.close();
}
document.save(outputPath);
}
finally
{
document.close();
}
}
using org.apache.pdfbox.pdmodel;
using org.apache.pdfbox.pdmodel.edit;
using org.apache.pdfbox.pdmodel.font;
public void AddWatermark(string inputPath, string outputPath, string watermarkText)
{
PDDocument document = PDDocument.load(new File(inputPath));
try
{
PDFont font = PDType1Font.HELVETICA_BOLD;
for (int i = 0; i < document.getNumberOfPages(); i++)
{
PDPage page = document.getPage(i);
PDPageContentStream cs = new PDPageContentStream(
document, page, PDPageContentStream.AppendMode.APPEND, true, true);
cs.beginText();
cs.setFont(font, 72);
cs.setNonStrokingColor(200, 200, 200);
cs.setTextMatrix(Matrix.getRotateInstance(Math.toRadians(45), 200, 400));
cs.showText(watermarkText);
cs.endText();
cs.close();
}
document.save(outputPath);
}
finally
{
document.close();
}
}
Imports org.apache.pdfbox.pdmodel
Imports org.apache.pdfbox.pdmodel.edit
Imports org.apache.pdfbox.pdmodel.font
Public Sub AddWatermark(inputPath As String, outputPath As String, watermarkText As String)
Dim document As PDDocument = PDDocument.load(New File(inputPath))
Try
Dim font As PDFont = PDType1Font.HELVETICA_BOLD
For i As Integer = 0 To document.getNumberOfPages() - 1
Dim page As PDPage = document.getPage(i)
Dim cs As New PDPageContentStream(document, page, PDPageContentStream.AppendMode.APPEND, True, True)
cs.beginText()
cs.setFont(font, 72)
cs.setNonStrokingColor(200, 200, 200)
cs.setTextMatrix(Matrix.getRotateInstance(Math.toRadians(45), 200, 400))
cs.showText(watermarkText)
cs.endText()
cs.close()
Next
document.save(outputPath)
Finally
document.close()
End Try
End Sub
IronPDF實現:
using IronPdf;
public void AddWatermark(string inputPath, string outputPath, string watermarkText)
{
using var pdf = PdfDocument.FromFile(inputPath);
pdf.ApplyWatermark(
$"<h1 style='color:lightgray;font-size:72px;'>{watermarkText}</h1>",
rotation: 45,
opacity: 50);
pdf.SaveAs(outputPath);
}
using IronPdf;
public void AddWatermark(string inputPath, string outputPath, string watermarkText)
{
using var pdf = PdfDocument.FromFile(inputPath);
pdf.ApplyWatermark(
$"<h1 style='color:lightgray;font-size:72px;'>{watermarkText}</h1>",
rotation: 45,
opacity: 50);
pdf.SaveAs(outputPath);
}
Imports IronPdf
Public Sub AddWatermark(inputPath As String, outputPath As String, watermarkText As String)
Using pdf = PdfDocument.FromFile(inputPath)
pdf.ApplyWatermark(
$"<h1 style='color:lightgray;font-size:72px;'>{watermarkText}</h1>",
rotation:=45,
opacity:=50)
pdf.SaveAs(outputPath)
End Using
End Sub
IronPDF的基於HTML的浮水印消除了頁面迭代和矩陣計算。
URL 到 PDF 轉換
Apache PDFBox不支援URL到PDF轉換。IronPDF提供原生支持:
using IronPdf;
public void ConvertUrlToPdf(string url, string outputPath)
{
var renderer = new ChromePdfRenderer();
using var pdf = renderer.RenderUrlAsPdf(url);
pdf.SaveAs(outputPath);
}
using IronPdf;
public void ConvertUrlToPdf(string url, string outputPath)
{
var renderer = new ChromePdfRenderer();
using var pdf = renderer.RenderUrlAsPdf(url);
pdf.SaveAs(outputPath);
}
Imports IronPdf
Public Sub ConvertUrlToPdf(url As String, outputPath As String)
Dim renderer As New ChromePdfRenderer()
Using pdf = renderer.RenderUrlAsPdf(url)
pdf.SaveAs(outputPath)
End Using
End Sub
有關完整的 URL 轉換選項,請參見URL 到 PDF 文件。
頭部和尾部
Apache PDFBox要求在每個頁面上進行手動定位,且不支持內建的頁眉/頁腳。 IronPDF提供了聲明式配置:
using IronPdf;
public void CreatePdfWithHeaderFooter(string html, string outputPath)
{
var renderer = new ChromePdfRenderer();
renderer.RenderingOptions.TextHeader = new TextHeaderFooter
{
CenterText = "Document Title",
FontSize = 12
};
renderer.RenderingOptions.TextFooter = new TextHeaderFooter
{
CenterText = "Page {page} of {total-pages}",
FontSize = 10
};
using var pdf = renderer.RenderHtmlAsPdf(html);
pdf.SaveAs(outputPath);
}
using IronPdf;
public void CreatePdfWithHeaderFooter(string html, string outputPath)
{
var renderer = new ChromePdfRenderer();
renderer.RenderingOptions.TextHeader = new TextHeaderFooter
{
CenterText = "Document Title",
FontSize = 12
};
renderer.RenderingOptions.TextFooter = new TextHeaderFooter
{
CenterText = "Page {page} of {total-pages}",
FontSize = 10
};
using var pdf = renderer.RenderHtmlAsPdf(html);
pdf.SaveAs(outputPath);
}
Imports IronPdf
Public Sub CreatePdfWithHeaderFooter(html As String, outputPath As String)
Dim renderer = New ChromePdfRenderer()
renderer.RenderingOptions.TextHeader = New TextHeaderFooter With {
.CenterText = "Document Title",
.FontSize = 12
}
renderer.RenderingOptions.TextFooter = New TextHeaderFooter With {
.CenterText = "Page {page} of {total-pages}",
.FontSize = 10
}
Using pdf = renderer.RenderHtmlAsPdf(html)
pdf.SaveAs(outputPath)
End Using
End Sub
有關高級佈局,請查看頁眉和頁腳文件。
ASP.NET Core 整合
IronPDF自然地與現代.NET web應用程式整合:
[HttpPost]
public IActionResult GeneratePdf([FromBody] ReportRequest request)
{
var renderer = new ChromePdfRenderer();
using var pdf = renderer.RenderHtmlAsPdf(request.Html);
return File(pdf.BinaryData, "application/pdf", "report.pdf");
}
[HttpPost]
public IActionResult GeneratePdf([FromBody] ReportRequest request)
{
var renderer = new ChromePdfRenderer();
using var pdf = renderer.RenderHtmlAsPdf(request.Html);
return File(pdf.BinaryData, "application/pdf", "report.pdf");
}
<HttpPost>
Public Function GeneratePdf(<FromBody> request As ReportRequest) As IActionResult
Dim renderer As New ChromePdfRenderer()
Using pdf = renderer.RenderHtmlAsPdf(request.Html)
Return File(pdf.BinaryData, "application/pdf", "report.pdf")
End Using
End Function
異步支持
Apache PDFBox移植不支援非同步操作。 IronPDF提供了完整的非同步/等待功能:
using IronPdf;
public async Task<byte[]> GeneratePdfAsync(string html)
{
var renderer = new ChromePdfRenderer();
using var pdf = await renderer.RenderHtmlAsPdfAsync(html);
return pdf.BinaryData;
}
using IronPdf;
public async Task<byte[]> GeneratePdfAsync(string html)
{
var renderer = new ChromePdfRenderer();
using var pdf = await renderer.RenderHtmlAsPdfAsync(html);
return pdf.BinaryData;
}
Imports IronPdf
Public Async Function GeneratePdfAsync(html As String) As Task(Of Byte())
Dim renderer As New ChromePdfRenderer()
Using pdf = Await renderer.RenderHtmlAsPdfAsync(html)
Return pdf.BinaryData
End Using
End Function
依賴注入配置
public interface IPdfService
{
Task<byte[]> GeneratePdfAsync(string html);
string ExtractText(string pdfPath);
}
public class IronPdfService : IPdfService
{
private readonly ChromePdfRenderer _renderer;
public IronPdfService()
{
_renderer = new ChromePdfRenderer();
_renderer.RenderingOptions.PaperSize = PdfPaperSize.A4;
}
public async Task<byte[]> GeneratePdfAsync(string html)
{
using var pdf = await _renderer.RenderHtmlAsPdfAsync(html);
return pdf.BinaryData;
}
public string ExtractText(string pdfPath)
{
using var pdf = PdfDocument.FromFile(pdfPath);
return pdf.ExtractAllText();
}
}
public interface IPdfService
{
Task<byte[]> GeneratePdfAsync(string html);
string ExtractText(string pdfPath);
}
public class IronPdfService : IPdfService
{
private readonly ChromePdfRenderer _renderer;
public IronPdfService()
{
_renderer = new ChromePdfRenderer();
_renderer.RenderingOptions.PaperSize = PdfPaperSize.A4;
}
public async Task<byte[]> GeneratePdfAsync(string html)
{
using var pdf = await _renderer.RenderHtmlAsPdfAsync(html);
return pdf.BinaryData;
}
public string ExtractText(string pdfPath)
{
using var pdf = PdfDocument.FromFile(pdfPath);
return pdf.ExtractAllText();
}
}
Imports System.Threading.Tasks
Public Interface IPdfService
Function GeneratePdfAsync(html As String) As Task(Of Byte())
Function ExtractText(pdfPath As String) As String
End Interface
Public Class IronPdfService
Implements IPdfService
Private ReadOnly _renderer As ChromePdfRenderer
Public Sub New()
_renderer = New ChromePdfRenderer()
_renderer.RenderingOptions.PaperSize = PdfPaperSize.A4
End Sub
Public Async Function GeneratePdfAsync(html As String) As Task(Of Byte()) Implements IPdfService.GeneratePdfAsync
Using pdf = Await _renderer.RenderHtmlAsPdfAsync(html)
Return pdf.BinaryData
End Using
End Function
Public Function ExtractText(pdfPath As String) As String Implements IPdfService.ExtractText
Using pdf = PdfDocument.FromFile(pdfPath)
Return pdf.ExtractAllText()
End Using
End Function
End Class
性能優化
記憶體使用比較
| 場景 | Apache PDFBox .NET移植 | IronPDF |
|---|---|---|
| 文字提取 | ~80 MB | ~50 MB |
| PDF建立 | ~100 MB | ~60 MB |
| 批次(100 PDFs) | 高(手動清理) | ~100 MB |
優化提示
使用using語句:
//自動cleanup with IDisposable pattern
using var pdf = PdfDocument.FromFile(path);
//自動cleanup with IDisposable pattern
using var pdf = PdfDocument.FromFile(path);
重用渲染器進行批量操作:
var renderer = new ChromePdfRenderer();
foreach (var html in htmlList)
{
using var pdf = renderer.RenderHtmlAsPdf(html);
pdf.SaveAs($"output_{i}.pdf");
}
var renderer = new ChromePdfRenderer();
foreach (var html in htmlList)
{
using var pdf = renderer.RenderHtmlAsPdf(html);
pdf.SaveAs($"output_{i}.pdf");
}
Imports IronPdf
Dim renderer As New ChromePdfRenderer()
For Each html In htmlList
Using pdf = renderer.RenderHtmlAsPdf(html)
pdf.SaveAs($"output_{i}.pdf")
End Using
Next
在 Web 應用中使用異步:
using var pdf = await renderer.RenderHtmlAsPdfAsync(html);
using var pdf = await renderer.RenderHtmlAsPdfAsync(html);
故障排除常見的遷移問題
問題:未找到Java風格的方法名稱
將camelCase Java方法替換為PascalCase .NET等效方法:
// PDFBox: stripper.getText(document)
// IronPDF: pdf.ExtractAllText()
// PDFBox: document.getNumberOfPages()
// IronPDF: pdf.PageCount
// PDFBox: stripper.getText(document)
// IronPDF: pdf.ExtractAllText()
// PDFBox: document.getNumberOfPages()
// IronPDF: pdf.PageCount
' PDFBox: stripper.getText(document)
' IronPDF: pdf.ExtractAllText()
' PDFBox: document.getNumberOfPages()
' IronPDF: pdf.PageCount
問題:沒有close()方法
IronPDF使用IDisposable模式:
// PDFBox
document.close();
// IronPDF
using var pdf = PdfDocument.FromFile(path);
//自動disposal at end of scope
// PDFBox
document.close();
// IronPDF
using var pdf = PdfDocument.FromFile(path);
//自動disposal at end of scope
' PDFBox
document.Close()
' IronPDF
Using pdf = PdfDocument.FromFile(path)
' 自動disposal at end of scope
End Using
問題:沒有PDFTextStripper等效
文字提取簡化為單一方法:
// IronPDF: Just call ExtractAllText()
string text = pdf.ExtractAllText();
// Per-page extraction:
string pageText = pdf.Pages[0].Text;
// IronPDF: Just call ExtractAllText()
string text = pdf.ExtractAllText();
// Per-page extraction:
string pageText = pdf.Pages[0].Text;
' IronPDF: Just call ExtractAllText()
Dim text As String = pdf.ExtractAllText()
' Per-page extraction:
Dim pageText As String = pdf.Pages(0).Text
問題:PDFMergerUtility 未找到
使用靜態Merge方法:
//IronPDFuses static Merge
var merged = PdfDocument.Merge(pdf1, pdf2, pdf3);
//IronPDFuses static Merge
var merged = PdfDocument.Merge(pdf1, pdf2, pdf3);
' IronPDF uses static Merge
Dim merged = PdfDocument.Merge(pdf1, pdf2, pdf3)
後遷移檢查清單
完成程式碼遷移後,請驗證以下內容:
- 運行所有現有的單元和整合測試
- 將 PDF 輸出與以前的版本進行視覺比較
- 測試文字提取準確性
- 驗證授權是否正常工作(
IronPdf.License.IsLicensed) - 性能與以前的實施做基準比較
- 更新CI/CD管道依賴性
- 記錄新的模式以供開發團隊參考
其他資源
從Apache PDFBox .NET移植到IronPDF,將您的PDF程式碼庫從Java風格模式轉換為典型的C#。 從手動坐標定位到HTML/CSS渲染的轉變,結合原生的非同步支援和現代.NET整合,提供了更乾淨、可維護的程式碼,以及在您生產應用程式背後的專業支援。

