From bdc5d2075876f2d087a0b415bdc3ec2e7f21ee0f Mon Sep 17 00:00:00 2001 From: Michael Dawson Date: Tue, 9 May 2017 22:58:08 +1000 Subject: [PATCH] Add image support (#8) Add support for decoding images in the RTF stream. --- bin/rtf_parse | 26 +++++++++++++++++++++++ lib/ruby-rtf/parser.rb | 11 ++++++++++ spec/parser_spec.rb | 47 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 84 insertions(+) diff --git a/bin/rtf_parse b/bin/rtf_parse index d8aa391..bd532a3 100755 --- a/bin/rtf_parse +++ b/bin/rtf_parse @@ -3,6 +3,7 @@ require 'ruby-rtf' require 'pp' +require 'base64' @prefix = '' @suffix = '' @@ -80,6 +81,28 @@ def format(str, section) str << @prefix + section[:text].force_encoding('UTF-8') + @suffix end +def process_image(section) + mods = section[:modifiers] + mime = '' + case mods[:picture_format] + when 'jpeg' + mime = 'image/jpg' + when 'png' + mime = 'image/png' + when 'bmp' + mime = 'image/bmp' + when 'wmf' + mime = 'image/x-wmf' + end + hex = section[:text].scan(/../).map(&:hex).pack('c*') + base64 = Base64.strict_encode64(hex) + width = 'auto' + width = mods[:picture_width] * (mods[:picture_scale_x] || 100) / 100 if mods[:picture_width] + height = 'auto' + height = mods[:picture_height] * (mods[:picture_scale_y] || 100) / 100 if mods[:picture_height] + "\n" +end + doc = RubyRTF::Parser.new.parse(File.open(ARGV[0]).read) STDERR.puts doc @@ -103,6 +126,9 @@ doc.sections.each do |section| end str << "\n" next + elsif mods[:picture] + str << process_image(section) + next end format(str, section) diff --git a/lib/ruby-rtf/parser.rb b/lib/ruby-rtf/parser.rb index 3261ba8..54a375c 100644 --- a/lib/ruby-rtf/parser.rb +++ b/lib/ruby-rtf/parser.rb @@ -279,6 +279,15 @@ def handle_control(name, val, src, current_pos) @context_stack.pop end + when :pict then add_section!(picture: true) + when :jpegblip then add_section!(picture_format:'jpeg') + when :pngblip then add_section!(picture_format:'png') + when *[:dibitmap, :wbitmap] then add_section!(picture_format:'bmp') + when *[:wmetafile, :pmmetafile] then add_section!(picture_format:'wmf') + when :pich then add_section!(picture_height: RubyRTF.twips_to_points(val)) + when :picw then add_section!(picture_width: RubyRTF.twips_to_points(val)) + when :picscalex then add_section!(picture_scale_x: val.to_i) + when :picscaley then add_section!(picture_scale_y: val.to_i) else unless @seen[name] @@ -514,7 +523,9 @@ def force_section!(mods = {}, text = nil) # # @return [Nil] def reset_current_section! + paragraph = current_section[:modifiers].has_key?(:paragraph) current_section[:modifiers].clear + current_section[:modifiers][:paragraph] = true if paragraph end def current_context diff --git a/spec/parser_spec.rb b/spec/parser_spec.rb index 472fed8..741b178 100644 --- a/spec/parser_spec.rb +++ b/spec/parser_spec.rb @@ -94,6 +94,53 @@ section[2][:text].should == 'Goodbye, cruel world.' end + context 'parses pictures' do + let(:src_bitmap) do + src = '{\rtf1 {\pict\wbitmap\picw7064\pich5292\picwgoal4005\pichgoal3000\picscalex111\picscaley109 +ffd8ffe000104a4649460001010100b400b40000ffe1158a687474703a2f2f6e732e61646f62652e636f6d2f7861702f3}}' + end + let(:src_jpeg) do + src = '{\rtf1 {\pict\jpegblip\picw7064\pich5292\picwgoal4005\pichgoal3000\picscalex111\picscaley109 +ffd8ffe000104a4649460001010100b400b40000ffe1158a687474703a2f2f6e732e61646f62652e636f6d2f7861702f3}}' + end + + it 'should parse jpeg' do + section = parser.parse(src_jpeg).sections + section[0][:modifiers][:picture].should be_true + section[0][:modifiers][:picture_format].should == 'jpeg' + end + + it 'should parse bmp' do + section = parser.parse(src_bitmap).sections + section[0][:modifiers][:picture].should be_true + section[0][:modifiers][:picture_format].should == 'bmp' + section = parser.parse(src_bitmap).sections + section[0][:modifiers][:picture].should be_true + section[0][:modifiers][:picture_format].should == 'bmp' + end + + it 'should parse width' do + section = parser.parse(src_bitmap).sections + section[0][:modifiers][:picture_width].should == 7064 / 20.0 + end + + it 'should parse height' do + section = parser.parse(src_bitmap).sections + section[0][:modifiers][:picture_height].should == 5292 / 20.0 + end + + it 'should parse scale' do + section = parser.parse(src_bitmap).sections + section[0][:modifiers][:picture_scale_x].should == 111 + section[0][:modifiers][:picture_scale_y].should == 109 + end + + it 'should parse picture data' do + section = parser.parse(src_bitmap).sections + section[0][:text].should == 'ffd8ffe000104a4649460001010100b400b40000ffe1158a687474703a2f2f6e732e61646f62652e636f6d2f7861702f3' + end + end + it 'clears ul with ul0' do src = '{\rtf1 \ul\b Hello\b0\ul0 World}' section = parser.parse(src).sections