如何使用 iTextSharp 将 HTML 转换为 PDF

2023-12-02

我想使用 iTextSharp 将以下 HTML 转换为 PDF,但不知道从哪里开始:

<style>
.headline{font-size:200%}
</style>
<p>
  This <em>is </em>
  <span class="headline" style="text-decoration: underline;">some</span>
  <strong>sample<em> text</em></strong>
  <span style="color: red;">!!!</span>
</p>

首先,HTML 和 PDF 并不相关,尽管它们是大约在同一时间创建的。 HTML 旨在传达更高级别的信息,例如段落和表格。尽管有方法可以控制它,但最终还是由浏览器来绘制这些更高层次的概念。 PDF 旨在传达文件和文件must无论它们在何处呈现,“看起来”都是一样的。

在 HTML 文档中,您可能有一个 100% 宽的段落,根据显示器的宽度,它可能需要 2 行或 10 行,当您打印它时,它可能需要 7 行,当您在手机上查看它时,它可能需要取20行。然而,PDF 文件,must be独立于渲染设备,因此无论您的屏幕尺寸如何必须始终渲染完全一样。

因为musts如上所述,PDF 不支持“表格”或“段落”等抽象内容。 PDF 支持三种基本内容:文本、线条/形状和图像。(还有其他东西,例如注释和电影,但我在这里尽量保持简单。)在 PDF 中,您不会说“这是一个段落,浏览器做您的事情!”。相反,您会说,“使用这种精确的字体在这个精确的 X,Y 位置绘制此文本,不用担心,我之前已经计算过文本的宽度,所以我知道它将全部适合这条线”。你也不会说“这是一张桌子”,而是说“在这个确切的位置绘制这个文本,然后在我之前计算过的另一个确切的位置绘制一个矩形,所以我知道它会出现在文本周围”。

其次,iText 和 iTextSharp 解析 HTML 和 CSS。就是这样。 ASP.Net、MVC、Razor、Struts、Spring 等都是 HTML 框架,但 iText/iTextSharp 100% 不知道它们。与 DataGridViews、Repeaters、Templates、Views 等相同,它们都是特定于框架的抽象。这是your负责从您选择的框架中获取 HTML,iText 不会帮助您。如果你得到一个异常说The document has no pages或者你认为“iText 没有解析我的 HTML”,这几乎可以肯定你实际上并不 有 HTML,你只是认为你这样做。

第三,已经存在多年的内置类是HTMLWorker然而这已被替换为XMLWorker (Java / .Net)。零工作正在进行中HTMLWorker它不支持 CSS 文件,并且仅对最基本的 CSS 属性提供有限的支持,实际上某些标签上的中断。如果您没有看到此文件中的 HTML 属性或 CSS 属性和值那么它可能不受支持HTMLWorker. XMLWorker有时可能会更复杂,但这些并发症也make it more 可扩展的.

下面的 C# 代码展示了如何将 HTML 标签解析为 iText 抽象,这些抽象会自动添加到您正在处理的文档中。 C# 和 Java 非常相似,因此转换应该相对容易。示例#1 使用内置HTMLWorker解析 HTML 字符串。由于仅支持内联样式class="headline"被忽略,但其他一切都应该有效。示例 #2 与第一个示例相同,只是它使用了XMLWorker反而。示例 #3 还解析了简单的 CSS 示例。

//Create a byte array that will eventually hold our final PDF
Byte[] bytes;

//Boilerplate iTextSharp setup here
//Create a stream that we can write to, in this case a MemoryStream
using (var ms = new MemoryStream()) {

    //Create an iTextSharp Document which is an abstraction of a PDF but **NOT** a PDF
    using (var doc = new Document()) {

        //Create a writer that's bound to our PDF abstraction and our stream
        using (var writer = PdfWriter.GetInstance(doc, ms)) {

            //Open the document for writing
            doc.Open();

            //Our sample HTML and CSS
            var example_html = @"<p>This <em>is </em><span class=""headline"" style=""text-decoration: underline;"">some</span> <strong>sample <em> text</em></strong><span style=""color: red;"">!!!</span></p>";
            var example_css = @".headline{font-size:200%}";

            /**************************************************
             * Example #1                                     *
             *                                                *
             * Use the built-in HTMLWorker to parse the HTML. *
             * Only inline CSS is supported.                  *
             * ************************************************/

            //Create a new HTMLWorker bound to our document
            using (var htmlWorker = new iTextSharp.text.html.simpleparser.HTMLWorker(doc)) {

                //HTMLWorker doesn't read a string directly but instead needs a TextReader (which StringReader subclasses)
                using (var sr = new StringReader(example_html)) {

                    //Parse the HTML
                    htmlWorker.Parse(sr);
                }
            }

            /**************************************************
             * Example #2                                     *
             *                                                *
             * Use the XMLWorker to parse the HTML.           *
             * Only inline CSS and absolutely linked          *
             * CSS is supported                               *
             * ************************************************/

            //XMLWorker also reads from a TextReader and not directly from a string
            using (var srHtml = new StringReader(example_html)) {

                //Parse the HTML
                iTextSharp.tool.xml.XMLWorkerHelper.GetInstance().ParseXHtml(writer, doc, srHtml);
            }

            /**************************************************
             * Example #3                                     *
             *                                                *
             * Use the XMLWorker to parse HTML and CSS        *
             * ************************************************/

            //In order to read CSS as a string we need to switch to a different constructor
            //that takes Streams instead of TextReaders.
            //Below we convert the strings into UTF8 byte array and wrap those in MemoryStreams
            using (var msCss = new MemoryStream(System.Text.Encoding.UTF8.GetBytes(example_css))) {
                using (var msHtml = new MemoryStream(System.Text.Encoding.UTF8.GetBytes(example_html))) {

                    //Parse the HTML
                    iTextSharp.tool.xml.XMLWorkerHelper.GetInstance().ParseXHtml(writer, doc, msHtml, msCss);
                }
            }


            doc.Close();
        }
    }

    //After all of the PDF "stuff" above is done and closed but **before** we
    //close the MemoryStream, grab all of the active bytes from the stream
    bytes = ms.ToArray();
}

//Now we just need to do something with those bytes.
//Here I'm writing them to disk but if you were in ASP.Net you might Response.BinaryWrite() them.
//You could also write the bytes to a database in a varbinary() column (but please don't) or you
//could pass them to another function for further PDF processing.
var testFile = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "test.pdf");
System.IO.File.WriteAllBytes(testFile, bytes);

2017年更新

对于 HTML 到 PDF 的需求有好消息。作为这个答案表明, W3C 标准CSS-break-3将解决问题...这是一个候选推荐,计划在测试后于今年变成最终推荐。

由于不太标准,有一些解决方案,带有 C# 插件,如所示print-css.rocks.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何使用 iTextSharp 将 HTML 转换为 PDF 的相关文章

  • Qt - QProcess 不工作

    我尝试启动 Internet Explorer 所以我使用下面的代码 QProcess process new QProcess this QString temp C Program Files Internet Explorer iex
  • 更新面板工作速度非常慢

    我正在编写一个用户可以注册的应用程序 注册时 可以选择多个选项 并根据这些注册字段可见或不可见以及是否必需 我想出了一个想法 所有字段都将位于 updatePanel 中 当用户更改注册选项时 我将在服务器端设置这些字段的可见性 它可以工作
  • C# 方法重载决策不选择具体的泛型覆盖

    这个完整的 C 程序说明了这个问题 public abstract class Executor
  • 使用 CMake 时如何导出 Emscripten 中的 C 函数

    In 本教程 https emscripten org docs porting connecting cpp and javascript Interacting with code html interacting with code
  • Environment.CurrentDirectory 与 System.IO.Directory.GetCurrentDirectory

    我正在编写一个 Net WinForms 并不断在调试和发布配置之间切换 并且有一些文件我需要任一配置才能访问 我想做的是将文件放在 BIN 文件夹中的公共目录中 这样它看起来像这样 MyProject Bin CommonFiles My
  • 转换 const void*

    我有一个函数返回一个const void 我想用它的信息作为char 我可以将它投射为 C 风格的罚款 char variable但是当我尝试使用reinterpret cast like reinterpret cast
  • 按扩展名过滤搜索文件返回太多结果

    我正在开发一个 C 控制台应用程序 它必须管理 Windows 操作系统上的文件 我需要获取具有特定扩展名的文件名 列表 我找到了很多解决方案 最建议的是以下一种 HANDLE hFind WIN32 FIND DATA data hFin
  • 现代 C++ 编译器是否能够在某些情况下避免调用 const 函数两次?

    例如 如果我有以下代码 class SomeDataProcessor public bool calc const SomeData d1 const SomeData d2 const private Some non mutable
  • 无法注册时间触发的后台任务

    对于 Windows 8 应用程序 在 C Xaml 中 我尝试注册后台任务 很难说 但我想我的后台任务已正确注册 但是当我单击调试位置工具栏上的后台任务名称时 我的应用程序停止工作 没有任何消息 我查看了事件查看器上的日志 得到 具有入口
  • 如何将 .txt 文件中的数据转换为 xml? C#

    我在一个文本文件中有数千行数据 我想通过将其转换为更容易搜索的内容来轻松搜索 我希望 XML 或其他类型的大型数据结构 尽管我不确定它是否是最好的对于我的想法 每行的数据如下所示 第 31 册 托马斯 乔治 32 34 154 每本书都不是
  • 如何在 C# Designer.cs 代码中使用常量字符串?

    如何在 designer cs 文件中引用常量字符串 一个直接的答案是在我的 cs 文件中创建一个私有字符串变量 然后编辑 Designer cs 文件以使用此变量 而不是对字符串进行硬编码 但设计者不喜欢这样抛出错误 我明白为什么这行不通
  • 如何使用 x64 运行 cl?

    我遇到了和这里同样的问题致命错误 C1034 windows h 未设置包含路径 https stackoverflow com questions 931652 fatal error c1034 windows h no include
  • 在 .NET MAUI 中实现 TouchTracking

    我一直致力于将我们的应用程序从 Xamarin Forms 迁移到 NET MAUI 我们的应用程序几乎没有绘图功能 用户可以用手指进行绘图 我们用了TouchTrackingXamarin Forms 中的 nuget 包 但与 NET
  • 从 C# 使用 Odbc 调用 Oracle 包函数

    我在 Oracle 包中定义了一个函数 CREATE OR REPLACE PACKAGE BODY TESTUSER TESTPKG as FUNCTION testfunc n IN NUMBER RETURN NUMBER as be
  • 在 C# 中为父窗体中的子窗体控件添加事件处理程序

    我有两种形式 一种是带有按钮和文本框的父表单 单击该按钮时 将打开一个对话框 该子窗体又包含一个文本框和一个按钮 现在我想要的是 每当子表单文本框中的文本更改时 父表单文本框中的文本会自动更改 为了获得这个 我所做的是 Form3 f3 n
  • memcpy/memmove 到联合成员,这是否设置“活动”成员?

    重要说明 一些评论者似乎认为我是从工会抄袭的 仔细看memcpy 它从普通旧地址复制uint32 t 它不包含在联合中 另外 我正在复制 通过memcpy 到工会的特定成员 u a16 or u x in a union 不直接到整个联盟本
  • 如何在 C# 中创建异步方法?

    我读过的每一篇博客文章都会告诉您如何在 C 中使用异步方法 但由于某些奇怪的原因 从未解释如何构建您自己的异步方法来使用 所以我现在有这段代码使用我的方法 private async void button1 Click object se
  • 比较:接口方法、虚方法、抽象方法

    它们各自的优点和缺点是什么 接口方法 虚拟方法 抽象方法 什么时候应该选择什么 做出这一决定时应牢记哪些要点 虚拟和抽象几乎是一样的 虚方法在基类中有一个实现 可以选择重写 而抽象方法则没有 并且must在子类中被覆盖 否则它们是相同的 在
  • 使动态创建的链接标签在 Winforms 中可点击

    我正在制作一个程序 允许用户单击由动态链接标签创建的公司名称 在我想知道如何做到这一点之前 我从未在 C 中使用过链接标签 可为特定用户生成的业务数量各不相同 因此每个用户的链接标签数量并不相同 然后我想捕获业务 ID 以进行 Json 调
  • EntityFramework 6.0.0.0 读取数据,但不插入

    我创建了一个基于服务的数据库 folderName gt Add New Item gt Data gt Service based Database文件到 WPF 应用程序中 然后我用过Database First方法并创建了Person

随机推荐

  • iOS 从 CoreData 获取按主键排序的对象

    我已使用 CoreData 将数据保存到数据库中 我需要按照保存数据的顺序从表中获取数据 在表内 它按 Z PK 排序 隐藏的 CoreData 键 我怎样才能创建这样的排序描述符 如果我使用没有排序描述符的获取请求 我的数据对象的顺序错误
  • 更新 ClearCase 快照视图时出错

    我有一名用户 只有一名 其他人都很好 尝试更新他们的 ClearCase 视图 从过去 6 个月到今天 它一直对他们有效 当他们更新时 他们会得到 Unable to read directory Permission denied Err
  • 使用实体类型和键查找实体条目

    如何根据实体的键值和实体类型查找跟踪实体 我的意思是类似的东西DbSet
  • Django + Heroku + MongoDB Atlas (Djongo) = DatabaseError 无一例外

    问题的一行描述 每当我部署在 heroku 上的 django 应用程序尝试访问我的 MongoDB Atlas 集群以提交表单或检查管理员登录时 它都会抛出类似附加错误的内容 额外细节 Heroku 构建上可重现错误here 我认为这个错
  • MySQL - 如何连接两个表而不重复?

    我有两个如下表 hotels hotelID hotelName 第二张桌子 operators opID opName opServices opHotelID 简短的解释 在第一个表中 我有很多酒店 它们都有一个唯一的增量 id 第二个
  • 定位边界二维实体

    给定一个点和一组任意 2D 实体 圆 多边形 直线 折线 圆弧等 有谁知道现有的策略 确定该点是否被任何实体组合包围 界定 我知道对闭合形状进行 内部 测试很容易 但这并不总是能给我想要的东西 特别是对于嵌套或相交的形状 找到围绕我的点形成
  • 在 pandas 数据框中完全打印很长的字符串

    我正在为看似非常简单的事情而挣扎 我有一个包含很长字符串的 pandas 数据框 df pd DataFrame one one two This is very long string very long string very long
  • Python 3.9.1 的 dlib 安装错误。如何知道哪个版本兼容?

    我已经安装了 CMake 现在正在尝试为人脸识别项目安装 dlib 我看过一些视频 问题似乎是兼容性问题 对于 Python 3 9 1 哪个版本的 dlib 更兼容 我尝试使用 pip 安装 dlib 手动下载它 但仍然显示以下错误 WA
  • 当原型包含对象时访问“this”值?

    我有一个class像这样 function Foo this current 1 Foo prototype history Foo prototype history back function if this current undef
  • SQL复杂动态透视2

    您好 我正在尝试在 SQL Server 中进行下表的旋转 REFID COL1 COL2 Sequence 1 abc cde 1 1 lmn rst 2 1 kna asg 3 2 als zkd 2 2 zpk lad 1 我想要的输
  • 尽管有通用约束,C# 类型转换还是错误

    为什么在类 P 的类型参数 T 的泛型约束为 必须从 A 继承 的情况下 第一次调用会成功 但第二次调用会失败 并出现注释中详细说明的类型转换错误 abstract class A static class S public static
  • 三元条件中的意外标记中断

    下面的函数旨在以数组形式从 可能嵌套的 对象返回值 列表参数可以是任何对象 如果我将break语句移到for循环之后 我不会收到任何错误 但当然我的函数不会按需要运行 我使用break的方式有什么问题吗 function listToArr
  • Eclipse - 无法从“https://services.gradle.org/distributions/gradle-2.1-bin.zip”安装 Gradle 发行版

    我正在尝试在 Eclipse 中创建一个新的 gradle 项目 由于安全原因 Eclipse无法下载任何插件 软件 当我尝试创建 gradle 项目时 出现以下错误 无法找到请求目标的有效证书路径 可能 不安装 Gradle 发行版 ht
  • 定义我的轴的限制,但在两个方向上具有相同的比例[重复]

    这个问题在这里已经有答案了 我如何结合这些陈述 pyplot axis 1234 0 1773 0 497 0 1362 0 pyplot axis equal 我只想定义轴的限制 但在两个方向上具有相同的比例 PS 我试过了pyplot
  • 在 Python 中将 GET 请求代理到不同的站点

    我想将从客户端收到的 GET 请求转发到另一个站点 就我而言 m3u8 播放列表请求流媒体站点进行处理 有谁知道该怎么做 如果要代理 请先安装requests pip install requests 然后 获取服务器中的文件并提供内容 e
  • Solr 拼写检查:无法显示结果,总是收到相同的错误

    所以 我对 solr 还很陌生 也许我有很多理解问题 我现在想做的是对我的搜索栏的自动建议 例如 如果您写 glves 结果应该是 gloves 这是一个自动完成功能 现在运行良好 但是 当然 当我输入 glves 时 什么也没有出现 现在
  • android @Suppress 错误与 @TargetApi

    有时 我会为可能运行我的应用程序的某些 Android 版本编写代码 使用最新 Android 工具的 Eclipse 仍然注意到我的 Manifest 文档允许较低版本的 Android 因此判定我的代码中有错误 解决这个问题的方法是添加
  • AX的源文件存放在哪里?

    我想 仅 对 Dynamics Ax 2009 的源文件 即 XPO 源文件 运行定期 每 4 小时 备份 我想知道它们的物理存储位置 AX7 所有元数据都以 XML 形式存储 方法也存储在常规文件中 并存储在版本控制中 See 本概述 A
  • 如何为 Dash/Plotly 中的下拉菜单命名

    我对破折号还很陌生 我试图弄清楚如何将名称放置在下拉菜单和滑块上方 并在它们之间提供一些间隙 我在侧面而不是在下拉列表的顶部得到这些名称 数据集 模型类型 这是我一直在使用的代码 html Div className row childre
  • 如何使用 iTextSharp 将 HTML 转换为 PDF

    我想使用 iTextSharp 将以下 HTML 转换为 PDF 但不知道从哪里开始 p This em is em span class headline some span strong sample em text em strong