ruby-rtf
| Language | Ruby |
|---|---|
| License | MIT |
| Repository | github.com/dj2/Ruby-RTF |
| Documentation | README, example converter in bin/rtf_parse |
| Depends on | nothing |
| Read / write | reads RTF; doesn't write RTF |
ruby-rtf parses an RTF string with RubyRTF::Parser.new.parse(src) and returns a RubyRTF::Document. The document has font_table, colour_table (alias color_table) and sections. Each section is a hash with :text and :modifiers: :bold, :italic, :underline, :font, :font_size, :foreground_colour, :paragraph, :newline, :tab, special characters like :emdash and :rquote, and :table for tables. Pictures come through as sections with :picture and hex data.
The parser covers common documents but not the whole spec. By default it warns about control words it doesn’t know; pass unknown_control_warning_enabled: false to silence that. The last gem release (0.0.5) is from 2020.
Installation#
gem install ruby-rtf
Basic usage: extract text from an RTF file#
require "ruby-rtf"
doc = RubyRTF::Parser.new(unknown_control_warning_enabled: false).parse(File.read("letter.rtf"))
text = +""
doc.sections.each do |section|
mods = section[:modifiers]
if mods[:paragraph]
text << "\n"
elsif mods[:tab]
text << "\t"
end
text << section[:text].to_s.dup.force_encoding("UTF-8") # \line sections carry "\n"
end
puts text
How to convert RTF to simple HTML#
require "cgi"
require "ruby-rtf"
doc = RubyRTF::Parser.new(unknown_control_warning_enabled: false).parse(File.read("letter.rtf"))
html = +"<p>"
doc.sections.each do |s|
m = s[:modifiers]
html << "</p>\n<p>" if m[:paragraph]
html << "<br>" if m[:newline]
next if s[:text].to_s.empty?
t = CGI.escapeHTML(s[:text].dup.force_encoding("UTF-8"))
t = "<b>#{t}</b>" if m[:bold]
t = "<i>#{t}</i>" if m[:italic]
t = "<u>#{t}</u>" if m[:underline]
html << t
end
html << "</p>"
puts html
The repository’s bin/rtf_parse script is a fuller converter with fonts, colors, tables and images.
How to list the fonts and colors#
doc.font_table.each { |font| puts font.name if font }
doc.color_table.each { |c| puts "rgb(#{c.red}, #{c.green}, #{c.blue})" if c && !c.use_default? }
How to read tables#
doc.sections.each do |s|
table = s[:modifiers][:table]
next unless table
table.rows.each do |row|
puts row.cells.map { |cell| cell.sections.map { |cs| cs[:text] }.join }.join(" | ")
end
end
Tips#
section[:text]can be binary-encoded;force_encoding("UTF-8")as above, like the bundled script does.- Font sizes in
:font_sizeare in points (RTF stores half-points). - For documents the parser can’t handle, convert with LibreOffice or Pandoc first.