RTF 转 HTML - VB.NET





4.00/5 (3投票s)
仍在开发中,但这是一个简单的 HTML 到 RTF 转换器
引言
我需要将 HTML 转换为 RTF,因为我想将 RTF 输出用于另一个不支持 HTML 但支持 RTF 的应用程序。
背景
我的客户希望能够打印动态生成的邮件合并文档,但报表编写软件组件只支持 RTF,而 Web 界面的编辑器只生成 HTML。
我研究了一些可能的解决方案
- 使用 Word - 这并不可行,因为这意味着要在 Web 服务器上安装 Office,使用 OLE 自动化,并希望您的 Web 服务器不会耗尽内存。费用约为 250 美元。
- 查找可以添加到 Bin 文件夹的 DLL - 只找到了一些解决方案,但每个解决方案的开发者许可证和服务器许可证加起来都要大约 299 美元。
- 更改为 Cute-Editor,因为它除了 HTML 格式外,还能保存 RTF 格式,费用为 250 美元。
告诉客户他们的软件需求将花费更多钱,这并不是一个很好的选择,因为您可能会失去业务和推荐,所以我必须从头开始重新思考这个问题。
经过更多的研究,我开始看到一些固定的模式和一些变化的模式,我还参考了维基百科,他们提供了一个简单的 RTF 格式示例。
{\rtf1\ansi{\fonttbl\f0\fswiss Helvetica;}\f0\pard This is some {\b bold} text.\par }
上面的 RTF 文本是简化的,分解如下:
\rtf1
= 告知您文档是 rtf 格式\ansi
= 使用 ANSI 字符集{\fonttbl\f0\fswiss Helvetica;}
= 将字体 0 定义为 Swiss(无衬线)Helvetica(如果可用)\f0
= 使用字体 0\pard
= 段落开始标记{\b bold}
= 只将此词加粗\par
= 段落结束标记- 第一个
{
和最后一个}
是文本字符串的分隔符。
在此之后,我决定我可以看到我能够玩弄 RTF 并看到每次更改的结果。
我从 Wordpad 中的简单“Hello World
”开始,然后用记事本打开它(RTF 就像 HTML 一样,是以人类可读的格式保存的 - 这最终看起来像这样:
{\rtf1\ansi\ansicpg1252\deff0\deflang2057{\fonttbl{\f0\fnil\fcharset0 Calibri;}}
{\*\generator Riched20 6.3.9600}\viewkind4\uc1
\pard\sa200\sl276\slmult1\qj\f0\fs22\lang9 Hello World\par
}
然后我将文本更改为粗体、斜体和下划线,并查看了更改。
我注意到 there were extra items like \viewkind4\uc1, \sa200\s1276\slmult1\qj & \fs22\lang9
.
回过头来研究这些附加项,发现其中一些很重要,有些则不那么重要。
\*\
- 这是一个注释条目\viewkind4
- 如果在 Word 中打开,显示为“普通视图”\uc1
- 使用主 Unicode 字符集\sa200
- 后续间距\s1276
- 与样式有关,但我还没有完全弄清楚\slmult1
- 单倍行距\qj
- 两端对齐文本(\ql
,\qr
,\qc
和\qd
是其他可用选项)\fs22
- Windows 字体大小 11(大小 * 2)\lang9
- 与语言有关,但我还没有弄清楚。
进展
至此,我已经掌握了客户要求的基本内容,并开始编码。在这个项目中,我只需要支持粗体、斜体和下划线文本,所以一开始我就专注于此。我也想要一些东西,即使存在其他不受支持的 HTML 元素,也不会崩溃。
代码
' =======================================================================
' = Define constants that are need to build the outline RTF file format =
' =======================================================================
' Define Start and End strings for RTF Formatting
Const RTF_START = "{\rtf1\ansi\ansicpg1252\deff0\deflang1033"
Const RTF_END = "}"
' Define Start and End strings for FONT tables
Const FONT_TABLE_START = "{\fonttbl"
Const FONT_TABLE_END = "}"
' Define Start and End strings for COLOR tables (Next version maybe)
'Const COLOR_TABLE_START = "{\colortbl "
'Const COLOR_TABLE_END = ";}"
' Define End Paragraph constant
Const LINE_BREAK = "\par" & vbCrLf
' Define Indent constant - No HTML equivalent ;-)
'Const RTF_TAB = "\tab "
' Define New Paragraph constant
Const NEW_PARAGRAPH = "\pard"
' Define Bold constants, as unlikely that you are only enboldening one character
Const BOLD_START = "\b "
Const BOLD_END = "\b0 "
' Define Underline constants
Const UNDERLINE_START = "\ul "
Const UNDERLINE_END = "\ul0 "
' Define Italic constants
Const ITALIC_START = "\i "
Const ITALIC_END = "\i0 "
' Define View and charset
Const DOCUMENT_START = "\viewkind4\uc1"
' ======================================================
' = RenderHTML =
' = =
' = Input : HTML encoded string (Content of body only) =
' = =
' = Output : RTF encoded string =
' = =
' ======================================================
Private Function RenderHTML(ByVal strInput As String) As String
Dim intPos As Integer
Dim strText As String
' Create initial header strings for the RTF format - Set font to Arial
strText = RTF_START + FONT_TABLE_START + "{\f0\fnil\fcharset0 Arial;}" + FONT_TABLE_END + vbCrLf
' Add view and charset
strText += DOCUMENT_START
' Start the document
strText += NEW_PARAGRAPH
' Set the font to Arial 11 and Justify the text
strText += "\sa200\sl276\slmult1\qj\f0\fs22\lang9 "
' Start Processing the HTML string
Do
' Check for < in HTML string
If Mid(strInput, 1, 1) = "<" Then
' Look for different tags and move input to next element in HTML
If Mid(strInput, 1, 3) = "<p>" Or Mid(strInput, 1, 3) = "<P>" Then
strInput = Mid(strInput, 4)
ElseIf Mid(strInput, 1, 4) = "</p>" Or Mid(strInput, 1, 3) = "</P>" Then
strText += LINE_BREAK
strInput = Mid(strInput, 5)
ElseIf Mid(strInput, 1, 3) = "<b>" Or Mid(strInput, 1, 3) = "<B>" Then
strText += BOLD_START
strInput = Mid(strInput, 4)
ElseIf Mid(strInput, 1, 4) = "</b>" Or Mid(strInput, 1, 3) = "</B>" Then
strText += BOLD_END
strInput = Mid(strInput, 5)
ElseIf Mid(strInput, 1, 3) = "<i>" Or Mid(strInput, 1, 3) = "<I>" Then
strText += ITALIC_START
strInput = Mid(strInput, 4)
ElseIf Mid(strInput, 1, 4) = "</i>" Or Mid(strInput, 1, 3) = "</I>" Then
strText += ITALIC_END
strInput = Mid(strInput, 5)
ElseIf Mid(strInput, 1, 8) = "<strong>" Or Mid(strInput, 1, 8) = "<STRONG>" Then
strText += BOLD_START
strInput = Mid(strInput, 9)
ElseIf Mid(strInput, 1, 9) = "</strong>" Or Mid(strInput, 1, 9) = "</STRONG>" Then
strText += BOLD_END
strInput = Mid(strInput, 10)
ElseIf Mid(strInput, 1, 4) = "<em>" Or Mid(strInput, 1, 4) = "<EM>" Then
strText += ITALIC_START
strInput = Mid(strInput, 5)
ElseIf Mid(strInput, 1, 5) = "</em>" Or Mid(strInput, 1, 5) = "</EM>" Then
strText += ITALIC_END
strInput = Mid(strInput, 6)
ElseIf Mid(strInput, 1, 3) = "<u>" Or Mid(strInput, 1, 3) = "<U>" Then
strText += UNDERLINE_START
strInput = Mid(strInput, 4)
ElseIf Mid(strInput, 1, 4) = "</u>" Or Mid(strInput, 1, 3) = "</U>" Then
strText += UNDERLINE_END
strInput = Mid(strInput, 5)
Else
' ============================================================================
' = Catch all remaining HTML and show on the browser the unsupported element =
' ============================================================================
intPos = InStr(strInput, ">")
HttpContext.Current.Response.Write("UNSUPPORTED : " + Mid(strInput, 1, intPos) + "<br/>")
strInput = Mid(strInput, intPos + 1)
End If
Else
' Check for & in the HTML input and replace
If Mid(strInput, 1, 1) = "&" Then
If Mid(strInput, 1, 6) = " " Then
strText += " "
strInput = Mid(strInput, 7)
ElseIf Mid(strInput, 1, 5) = "&" Then
strText += "&"
strInput = Mid(strInput, 6)
ElseIf Mid(strInput, 1, 4) = "<" Then
strText += "<"
strInput = Mid(strInput, 5)
ElseIf Mid(strInput, 1, 4) = ">" Then
strText += ">"
strInput = Mid(strInput, 5)
ElseIf Mid(strInput, 1, 6) = "©" Then
strText += "\'a9"
strInput = Mid(strInput, 7)
ElseIf Mid(strInput, 1, 5) = "®" Then
strText += "\'ae"
strInput = Mid(strInput, 6)
ElseIf Mid(strInput, 1, 7) = "™" Then
strText += "\'99"
strInput = Mid(strInput, 8)
ElseIf Mid(strInput, 1, 7) = "£" Then
strText += "£"
strInput = Mid(strInput, 8)
ElseIf Mid(strInput, 1, 6) = "€" Then
strText += "\'80"
strInput = Mid(strInput, 7)
ElseIf Mid(strInput, 1, 2) = "&#" Then
' Handle &#
If CType(Mid(strInput, 3, InStr(strInput, ";") - 1), Integer) <= 127 Then
strText += Chr(CType(Mid(strInput, 3, InStr(strInput, ";") - 1), Integer))
ElseIf CType(Mid(strInput, 3, InStr(strInput, ";") - 1), Integer) <= 255 Then
strText += "\'" + Hex(CType(Mid(strInput, 3, InStr(strInput, ";") - 1), Integer))
Else
strText += "\u" + Hex(CType(Mid(strInput, 3, InStr(strInput, ";") - 1), Integer))
End If
strInput = Mid(strInput, 3, InStr(strInput, ";") + 1)
Else
' ============================================================================
' = Catch all remaining HTML and show on the browser the unsupported element =
' ============================================================================
intPos = InStr(strInput, ";")
HttpContext.Current.Response.Write("UNSUPPORTED : " + Mid(strInput, 1, intPos) + "<br/>")
strInput = Mid(strInput, intPos + 1)
End If
Else
strText += Mid(strInput, 1, 1)
strInput = Mid(strInput, 2)
End If
End If
Loop Until strInput = ""
strText += RTF_END
Return strText
End Function
当前状态
正如你所见,存在一些不足之处
- 没有额外的字体支持
- 没有颜色支持
- 表格支持不足
我将在有时间和足够多的人感兴趣时开始研究这些问题,但由于其中大多数都嵌入在样式表或样式标签中,使用当前的编码模型,我需要多次解析 HTML 文件才能仅获取字体和颜色表,然后再获取实际文本,因此我正在开发一个更优雅的解决方案来解决这些问题,而且字体可能有多个选项,例如“Arial, Verdana, Helvetica, sans-serif”可能是样式属性,颜色可以是 #RRGGBB 或命名颜色,所以当我查看仅这些更改的时间尺度时,很明显需要采取额外的步骤。
我希望这段代码能帮助到其他人,如果您想以建设性的方式为这个技巧做出贡献,请随时与我联系并提出您的建议。