FO.NET與IronPDF:技術比較指南
當.NET開發者尋找PDF生成解決方案時,FO.NET因其將XSL-FO文件轉換為PDF的專業工具而脫穎而出。 然而,由於其依賴於過時的XSL-FO語言、缺乏HTML/CSS支援以及已停止維護的狀態,許多團隊考慮其他選擇。 IronPDF提供了一種使用HTML/CSS網頁標準的現代解決方案,大多數開發者已經熟悉這些標準,並具有Chromium渲染引擎和每月定期更新。
這次比較將對這兩個程式庫在相關技術方面進行審查,以協助專業開發者和架構師為其.NET PDF需求做出明智決策。
了解FO.NET
FO.NET(也被稱為FoNet)是一個開源程式庫,設計用來將XSL格式化物件(XSL-FO)文檔轉換成使用C#的PDF。 該程式庫運行在Apache 2.0授權下,直接將XSL-FO語言映射到PDF格式。
FO.NET使用Render()方法處理XSL-FO輸入流以生成PDF輸出流。 配置是在XSL-FO標記內部使用元素如fo:layout-master-set以及用於邊距、頁面大小和字體的格式屬性進行的。
一個顯著的限制是,FO.NET需要XSL-FO知識——這是一種XML基於的語言,從2001年W3C頒布以來,未自2006年進行過更新。該程式庫不支援HTML或CSS,無法直接渲染網頁。 XSL-FO在今天的技術領域大多數被認為是過時的,少於1%的開發者對它有專業知識,相較於超過98%了解HTML/CSS的開發者。
原始的CodePlex倉庫已經停止運行,GitHub衍生版本不再積極維護。 FO.NET對System.Drawing有內部依賴,阻止其在Linux/macOS上工作,僅限於Windows部署。
瞭解IronPDF
IronPDF是一個.NET PDF程式庫,使用HTML/CSS進行文件樣式和佈局,使用在開發中常用的網頁標準。 該程式庫使用Chromium渲染引擎,全面支援CSS3,包括Flexbox和Grid佈局,以及JavaScript執行。
IronPDF使用RenderingOptions則提供了程式化配置頁面尺寸、邊距、頁眉、頁腳和其他PDF設置。 該程式庫支援直接URL渲染、HTML字串渲染和HTML文件渲染,生成的PdfDocument對象可以儲存、合併、加密或進一步操作。
IronPDF積極維護,每月發布版本,支援真正的跨平台部署(Windows、Linux、macOS),並提供全面的文檔和教程。
架構與技術比較
這些.NET PDF程式庫之間的根本區別在於它們的輸入格式和技術基礎。
| 方面 | FO.NET | IronPDF |
|---|---|---|
| 輸入格式 | XSL-FO(過時的XML) | HTML/CSS(現代網絡標準) |
| 學習曲線 | 陡峭的(XSL-FO專業知識) | 溫和(HTML/CSS 知識) |
| 維護 | 已放棄 | 每月積極維護 |
| 平台支持 | 僅限Windows | 真正的跨平台 |
| CSS 支援 | None | 完整的CSS3 (Flexbox, Grid) |
| JavaScript | None | 完整的JavaScript支持 |
| URL渲染 | 不支持 | 內建 |
| 現代功能 | 有限 | 頁眉、頁腳、水印、安全性 |
| 文件資料 | 過時 | 詳細的教程 |
FO.NET是在XSL-FO預計成為文件格式標準的時候設計的。 這並沒有發生——HTML/CSS成為了通用的文件格式。 大多數XSL-FO資源於2005-2010年,這使得尋找最新的信息或社區支援變得越來越困難。
程式碼比較:常見的PDF操作
HTML到PDF的轉換
最基本的操作展示了XSL-FO和HTML方法之間的模型差異。
FO.NET:
// NuGet: Install-Package Fonet
using Fonet;
using Fonet.Render.Pdf;
using System.IO;
using System.Xml;
class Program
{
static void Main()
{
// FoNet requires XSL-FO format, not HTML
// First convert HTML to XSL-FO (manual process)
string xslFo = @"<?xml version='1.0' encoding='utf-8'?>
<fo:root xmlns:fo='http://www.w3.org/1999/XSL/Format'>
<fo:layout-master-set>
<fo:simple-page-master master-name='page'>
<fo:region-body/>
</fo:simple-page-master>
</fo:layout-master-set>
<fo:page-sequence master-reference='page'>
<fo:flow flow-name='xsl-region-body'>
<fo:block>Hello World</fo:block>
</fo:flow>
</fo:page-sequence>
</fo:root>";
FonetDriver driver = FonetDriver.Make();
driver.Render(new StringReader(xslFo),
new FileStream("output.pdf", FileMode.Create));
}
}// NuGet: Install-Package Fonet
using Fonet;
using Fonet.Render.Pdf;
using System.IO;
using System.Xml;
class Program
{
static void Main()
{
// FoNet requires XSL-FO format, not HTML
// First convert HTML to XSL-FO (manual process)
string xslFo = @"<?xml version='1.0' encoding='utf-8'?>
<fo:root xmlns:fo='http://www.w3.org/1999/XSL/Format'>
<fo:layout-master-set>
<fo:simple-page-master master-name='page'>
<fo:region-body/>
</fo:simple-page-master>
</fo:layout-master-set>
<fo:page-sequence master-reference='page'>
<fo:flow flow-name='xsl-region-body'>
<fo:block>Hello World</fo:block>
</fo:flow>
</fo:page-sequence>
</fo:root>";
FonetDriver driver = FonetDriver.Make();
driver.Render(new StringReader(xslFo),
new FileStream("output.pdf", FileMode.Create));
}
}Imports Fonet
Imports Fonet.Render.Pdf
Imports System.IO
Imports System.Xml
Module Program
Sub Main()
' FoNet requires XSL-FO format, not HTML
' First convert HTML to XSL-FO (manual process)
Dim xslFo As String = "<?xml version='1.0' encoding='utf-8'?>" & _
"<fo:root xmlns:fo='http://www.w3.org/1999/XSL/Format'>" & _
"<fo:layout-master-set>" & _
"<fo:simple-page-master master-name='page'>" & _
"<fo:region-body/>" & _
"</fo:simple-page-master>" & _
"</fo:layout-master-set>" & _
"<fo:page-sequence master-reference='page'>" & _
"<fo:flow flow-name='xsl-region-body'>" & _
"<fo:block>Hello World</fo:block>" & _
"</fo:flow>" & _
"</fo:page-sequence>" & _
"</fo:root>"
Dim driver As FonetDriver = FonetDriver.Make()
driver.Render(New StringReader(xslFo),
New FileStream("output.pdf", FileMode.Create))
End Sub
End ModuleIronPDF:
// NuGet: Install-Package IronPdf
using IronPdf;
class Program
{
static void Main()
{
var renderer = new ChromePdfRenderer();
string html = "<h1>Hello World</h1><p>This is HTML content.</p>";
var pdf = renderer.RenderHtmlAsPdf(html);
pdf.SaveAs("output.pdf");
}
}// NuGet: Install-Package IronPdf
using IronPdf;
class Program
{
static void Main()
{
var renderer = new ChromePdfRenderer();
string html = "<h1>Hello World</h1><p>This is HTML content.</p>";
var pdf = renderer.RenderHtmlAsPdf(html);
pdf.SaveAs("output.pdf");
}
}Imports IronPdf
Class Program
Shared Sub Main()
Dim renderer = New ChromePdfRenderer()
Dim html As String = "<h1>Hello World</h1><p>This is HTML content.</p>"
Dim pdf = renderer.RenderHtmlAsPdf(html)
pdf.SaveAs("output.pdf")
End Sub
End Class對比顯而易見。 FO.NET需要冗長的XSL-FO標記,並包含XML命名空間聲明、fo:block元素——這一切之後才能輸出簡單的"Hello World"文本。 代碼註解中明確指出:"FoNet需要XSL-FO格式,而不是HTML。"
IronPDF創建了一個渲染器,傳遞標準HTML,渲染為PDF並保存——四行簡單的語法使用開發者已知的語法。
有關進階HTML渲染選項,請查看HTML到PDF轉換指南。
URL到PDF轉換
將網頁轉換為PDF顯示了一個關鍵的能力差距。
FO.NET:
// NuGet: Install-Package Fonet
using Fonet;
using System.IO;
using System.Net;
class Program
{
static void Main()
{
// FoNet does not support URL rendering directly
// Must manually download, convert HTML to XSL-FO, then render
string url = "https://example.com";
string html = new WebClient().DownloadString(url);
// Manual conversion from HTML to XSL-FO required (complex)
string xslFo = ConvertHtmlToXslFo(html); // Not built-in
FonetDriver driver = FonetDriver.Make();
driver.Render(new StringReader(xslFo),
new FileStream("webpage.pdf", FileMode.Create));
}
static string ConvertHtmlToXslFo(string html)
{
// Custom implementation required
throw new System.NotImplementedException();
}
}// NuGet: Install-Package Fonet
using Fonet;
using System.IO;
using System.Net;
class Program
{
static void Main()
{
// FoNet does not support URL rendering directly
// Must manually download, convert HTML to XSL-FO, then render
string url = "https://example.com";
string html = new WebClient().DownloadString(url);
// Manual conversion from HTML to XSL-FO required (complex)
string xslFo = ConvertHtmlToXslFo(html); // Not built-in
FonetDriver driver = FonetDriver.Make();
driver.Render(new StringReader(xslFo),
new FileStream("webpage.pdf", FileMode.Create));
}
static string ConvertHtmlToXslFo(string html)
{
// Custom implementation required
throw new System.NotImplementedException();
}
}Imports Fonet
Imports System.IO
Imports System.Net
Class Program
Shared Sub Main()
' FoNet does not support URL rendering directly
' Must manually download, convert HTML to XSL-FO, then render
Dim url As String = "https://example.com"
Dim html As String = New WebClient().DownloadString(url)
' Manual conversion from HTML to XSL-FO required (complex)
Dim xslFo As String = ConvertHtmlToXslFo(html) ' Not built-in
Dim driver As FonetDriver = FonetDriver.Make()
driver.Render(New StringReader(xslFo),
New FileStream("webpage.pdf", FileMode.Create))
End Sub
Shared Function ConvertHtmlToXslFo(html As String) As String
' Custom implementation required
Throw New System.NotImplementedException()
End Function
End ClassIronPDF:
// NuGet: Install-Package IronPdf
using IronPdf;
class Program
{
static void Main()
{
var renderer = new ChromePdfRenderer();
var pdf = renderer.RenderUrlAsPdf("https://example.com");
pdf.SaveAs("webpage.pdf");
}
}// NuGet: Install-Package IronPdf
using IronPdf;
class Program
{
static void Main()
{
var renderer = new ChromePdfRenderer();
var pdf = renderer.RenderUrlAsPdf("https://example.com");
pdf.SaveAs("webpage.pdf");
}
}Imports IronPdf
Class Program
Shared Sub Main()
Dim renderer = New ChromePdfRenderer()
Dim pdf = renderer.RenderUrlAsPdf("https://example.com")
pdf.SaveAs("webpage.pdf")
End Sub
End ClassFO.NET明確表示不支援URL渲染。 代碼注釋中指出:"FoNet不直接支援URL渲染"和"需要從HTML到XSL-FO的手動轉換(複雜)。"因為這項轉換並非內建且需要自行實現,NotImplementedException。
IronPDF提供原生RenderUrlAsPdf()功能,處理URL抓取、JavaScript執行和渲染,一次方法調用即可——三行代碼對比複雜和未實現的工作流程。
了解有關URL渲染的更多信息,請參見URL to PDF文檔。
具有自定義設置的PDF
配置頁面尺寸和邊距展示了配置方法的差異。
FO.NET:
// NuGet: Install-Package Fonet
using Fonet;
using Fonet.Render.Pdf;
using System.IO;
class Program
{
static void Main()
{
// FoNet settings are configured in XSL-FO markup
string xslFo = @"<?xml version='1.0' encoding='utf-8'?>
<fo:root xmlns:fo='http://www.w3.org/1999/XSL/Format'>
<fo:layout-master-set>
<fo:simple-page-master master-name='A4'
page-height='297mm' page-width='210mm'
margin-top='20mm' margin-bottom='20mm'
margin-left='25mm' margin-right='25mm'>
<fo:region-body/>
</fo:simple-page-master>
</fo:layout-master-set>
<fo:page-sequence master-reference='A4'>
<fo:flow flow-name='xsl-region-body'>
<fo:block font-size='14pt'>Custom PDF</fo:block>
</fo:flow>
</fo:page-sequence>
</fo:root>";
FonetDriver driver = FonetDriver.Make();
driver.Render(new StringReader(xslFo),
new FileStream("custom.pdf", FileMode.Create));
}
}// NuGet: Install-Package Fonet
using Fonet;
using Fonet.Render.Pdf;
using System.IO;
class Program
{
static void Main()
{
// FoNet settings are configured in XSL-FO markup
string xslFo = @"<?xml version='1.0' encoding='utf-8'?>
<fo:root xmlns:fo='http://www.w3.org/1999/XSL/Format'>
<fo:layout-master-set>
<fo:simple-page-master master-name='A4'
page-height='297mm' page-width='210mm'
margin-top='20mm' margin-bottom='20mm'
margin-left='25mm' margin-right='25mm'>
<fo:region-body/>
</fo:simple-page-master>
</fo:layout-master-set>
<fo:page-sequence master-reference='A4'>
<fo:flow flow-name='xsl-region-body'>
<fo:block font-size='14pt'>Custom PDF</fo:block>
</fo:flow>
</fo:page-sequence>
</fo:root>";
FonetDriver driver = FonetDriver.Make();
driver.Render(new StringReader(xslFo),
new FileStream("custom.pdf", FileMode.Create));
}
}Imports Fonet
Imports Fonet.Render.Pdf
Imports System.IO
Class Program
Shared Sub Main()
' FoNet settings are configured in XSL-FO markup
Dim xslFo As String = "<?xml version='1.0' encoding='utf-8'?>" & _
"<fo:root xmlns:fo='http://www.w3.org/1999/XSL/Format'>" & _
"<fo:layout-master-set>" & _
"<fo:simple-page-master master-name='A4' " & _
"page-height='297mm' page-width='210mm' " & _
"margin-top='20mm' margin-bottom='20mm' " & _
"margin-left='25mm' margin-right='25mm'>" & _
"<fo:region-body/>" & _
"</fo:simple-page-master>" & _
"</fo:layout-master-set>" & _
"<fo:page-sequence master-reference='A4'>" & _
"<fo:flow flow-name='xsl-region-body'>" & _
"<fo:block font-size='14pt'>Custom PDF</fo:block>" & _
"</fo:flow>" & _
"</fo:page-sequence>" & _
"</fo:root>"
Dim driver As FonetDriver = FonetDriver.Make()
driver.Render(New StringReader(xslFo),
New FileStream("custom.pdf", FileMode.Create))
End Sub
End ClassIronPDF:
// NuGet: Install-Package IronPdf
using IronPdf;
using IronPdf.Engines.Chrome;
class Program
{
static void Main()
{
var renderer = new ChromePdfRenderer();
renderer.RenderingOptions.PaperSize = PdfPaperSize.A4;
renderer.RenderingOptions.MarginTop = 20;
renderer.RenderingOptions.MarginBottom = 20;
renderer.RenderingOptions.MarginLeft = 25;
renderer.RenderingOptions.MarginRight = 25;
string html = "<h1 style='font-size:14pt'>Custom PDF</h1>";
var pdf = renderer.RenderHtmlAsPdf(html);
pdf.SaveAs("custom.pdf");
}
}// NuGet: Install-Package IronPdf
using IronPdf;
using IronPdf.Engines.Chrome;
class Program
{
static void Main()
{
var renderer = new ChromePdfRenderer();
renderer.RenderingOptions.PaperSize = PdfPaperSize.A4;
renderer.RenderingOptions.MarginTop = 20;
renderer.RenderingOptions.MarginBottom = 20;
renderer.RenderingOptions.MarginLeft = 25;
renderer.RenderingOptions.MarginRight = 25;
string html = "<h1 style='font-size:14pt'>Custom PDF</h1>";
var pdf = renderer.RenderHtmlAsPdf(html);
pdf.SaveAs("custom.pdf");
}
}Imports IronPdf
Imports IronPdf.Engines.Chrome
Class Program
Shared Sub Main()
Dim renderer As New ChromePdfRenderer()
renderer.RenderingOptions.PaperSize = PdfPaperSize.A4
renderer.RenderingOptions.MarginTop = 20
renderer.RenderingOptions.MarginBottom = 20
renderer.RenderingOptions.MarginLeft = 25
renderer.RenderingOptions.MarginRight = 25
Dim html As String = "<h1 style='font-size:14pt'>Custom PDF</h1>"
Dim pdf = renderer.RenderHtmlAsPdf(html)
pdf.SaveAs("custom.pdf")
End Sub
End ClassFoNet代碼註釋中明確指出:"FoNet設置是在XSL-FO標記中配置的。" 頁面尺寸、邊距和格式以XML結構作為fo:simple-page-master上的屬性嵌入。 這意味著配置與內容交織在一個冗長的XML格式中。
IronPDF通過程式化的RenderingOptions屬性將配置與內容分開。 設置如MarginRight是在渲染器對象上設定的,而內容則保持為乾淨的HTML。
API映射參考
對於評估FO.NET遷移或比較功能的開發者,下面的映射顯示了相等的操作:
核心類對應
| FO.NET | IronPDF |
|---|---|
FonetDriver.Make() | new ChromePdfRenderer() |
driver.Render(inputStream, outputStream) | renderer.RenderHtmlAsPdf(html) |
driver.Render(inputFile, outputStream) | renderer.RenderHtmlFileAsPdf(path) |
driver.BaseDirectory | RenderingOptions.BaseUrl |
driver.OnError += handler | 在渲染周圍的try/catch |
XSL-FO到RenderingOptions的映射
| XSL-FO屬性 | IronPDF RenderingOptions |
|---|---|
page-width | PaperSize |
margin-top | MarginTop |
margin-bottom | MarginBottom |
margin-left | MarginLeft |
margin-right | MarginRight |
reference-orientation | PaperOrientation |
XSL-FO元素到HTML的映射
| XSL-FO元素 | HTML等效 | |
|---|---|---|
<fo:root> | <html> | |
<fo:layout-master-set> | CSS @page 規則 | |
<fo:simple-page-master> | CSS @page | |
<fo:page-sequence> | <body> 或 <div> | |
<fo:flow> | <main> 或 <div> | |
<fo:static-content> | HtmlHeaderFooter | |
<fo:block> | <p>, <div>, <h1>-<h6> | |
<fo:table> | <table> | |
<fo:list-block> | <ul>, <ol> | |
<fo:external-graphic> | <img> | |
<fo:page-number/> | {page} 占位符 |
功能比較總結
| 功能 | FO.NET | IronPDF |
|---|---|---|
| HTML到PDF | 否(需要手動XSL-FO轉換) | 是 |
| URL到PDF | 否(不支援) | 是 |
| XSL-FO到PDF | 是 | 不適用 |
| CSS3支援 | 無 | 是(Flexbox, Grid) |
| JavaScript | 無 | 是 |
| 頁首/頁腳 | XSL-FO靜態內容 | 基於HTML |
| 頁碼 | fo:page-number | {page} 占位符 |
| 跨平台 | 否(僅限Windows) | 是 |
| 積極維護 | 否(已放棄) | 是(每月) |
當團隊考慮從FO.NET轉向IronPDF時
開發團隊出於多種原因考慮從FO.NET過渡到IronPDF:
過時技術:XSL-FO是2001年的W3C規範,自2006年以來未進行任何更新,大多被認為是過時的。 大多數資源和文檔來自2005-2010年,因此尋找最新信息或僱用具有XSL-FO專業知識的開發者越來越困難。
陡峭的學習曲線:XSL-FO需要學習複雜的基於XML的標記,帶有專門的格式化物件(fo:page-sequence等)。 少於1%的開發者知道XSL-FO,相較於超過98%了解HTML/CSS的開發者。
無HTML/CSS支援:FO.NET無法渲染HTML或CSS——它需要從HTML到XSL-FO標記的手動轉換,這不內建在程式庫中。 擁有網頁內容或HTML模板的團隊必須實現自定義轉換邏輯。
已放棄的維護:原始的CodePlex倉庫已經停止運行,GitHub衍生版本不再積極維護。 安全補丁、錯誤修復和新功能不再被開發。
平台限制:FO.NET對System.Drawing有內部依賴,阻止其在Linux/macOS上工作,僅限於Windows部署。 現代應用越來越需要跨平台部署。
缺少現代功能:無JavaScript支援,無CSS3功能(Flexbox, Grid),無現代網頁字體,無直接URL渲染能力。
優勢和考量
FO.NET的優勢
- 直接XSL-FO轉換:專為XSL-FO轉PDF優化
- 開源:Apache 2.0授權——免費使用、修改和分發
- 精確控制:XSL-FO提供詳細的文件佈局控制
FO.NET的考量
- 過時技術:XSL-FO規範自2006年以來無更新
- 需要XSL-FO知識:少於1%的開發者擁有專業知識
- 無HTML支援:無法渲染HTML或CSS內容
- 已放棄:無積極維護或安全更新
- 僅限Windows:System.Drawing依賴阻止跨平台使用
- 無URL渲染:無法直接轉換網頁
- 有限的文檔:資源過時
IronPDF的優勢
IronPDF的考量
- 商業許可:需要生產使用的許可證
- 不同的範式:XSL-FO模板需要轉換為HTML
結論
FO.NET和IronPDF代表了.NET中PDF生成的根本不同方法。 FO.NET服務於XSL-FO到PDF轉換的專門應用,但其依賴於過時技術、中止維護、僅限於Windows和缺乏HTML支援,這使其越來越難以在新專案中證明其合理性。
IronPDF提供了一種使用HTML/CSS網頁標準的現代方法,與當前的開發者技能和技術保持一致。 直接渲染HTML、URL和使用具有Chromium引擎的完整CSS3的能力,使其適合當今的PDF生成需求。
隨著組織為.NET 10、C# 14和2026年的應用開發做準備,技術基礎至關重要。 雖然保留舊版XSL-FO系統的團隊可能繼續使用FO.NET,但現代PDF生成的發展路徑顯然指向了利用現有網開發專業知識的HTML解決方案,例如IronPDF。
開始評估IronPDF,通過免費試用,並查看更多詳細文檔,來評估其對您的具體需求是否合適。
