clbustos-rtf 0.4.2 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. data/.gemtest +0 -0
  2. data/History.txt +53 -0
  3. data/{LICENSE → LICENSE.txt} +0 -0
  4. data/Manifest.txt +52 -0
  5. data/README.rdoc +60 -63
  6. data/README.txt +201 -0
  7. data/Rakefile +18 -34
  8. data/examples/example01.rb +5 -1
  9. data/examples/example02.rb +1 -0
  10. data/examples/example03.rb +1 -0
  11. data/examples/example03.rtf +0 -0
  12. data/examples/example04.rb +1 -0
  13. data/examples/rubyrtf.bmp +0 -0
  14. data/examples/rubyrtf.jpg +0 -0
  15. data/examples/rubyrtf.png +0 -0
  16. data/ifad-rtf.gemspec +120 -0
  17. data/lib/rtf.rb +1 -0
  18. data/lib/rtf/colour.rb +0 -0
  19. data/lib/rtf/converters.rb +5 -0
  20. data/lib/rtf/converters/html.rb +123 -0
  21. data/lib/rtf/font.rb +0 -0
  22. data/lib/rtf/information.rb +0 -0
  23. data/lib/rtf/node.rb +136 -109
  24. data/lib/rtf/paper.rb +0 -0
  25. data/lib/rtf/style.rb +0 -0
  26. data/test/fixtures/bitmap1.bmp +0 -0
  27. data/test/fixtures/bitmap2.bmp +0 -0
  28. data/test/fixtures/jpeg1.jpg +0 -0
  29. data/test/fixtures/jpeg2.jpg +0 -0
  30. data/test/fixtures/png1.png +0 -0
  31. data/test/fixtures/png2.png +0 -0
  32. data/test/{test_helper.rb → helper_tests.rb} +1 -0
  33. data/test/{character_style_test.rb → test_character_style.rb} +1 -1
  34. data/test/{colour_test.rb → test_colour.rb} +2 -2
  35. data/test/{colour_table_test.rb → test_colour_table.rb} +2 -2
  36. data/test/{command_node_test.rb → test_command_node.rb} +1 -1
  37. data/test/{container_node_test.rb → test_container_node.rb} +2 -1
  38. data/test/{document_test.rb → test_document.rb} +1 -1
  39. data/test/{document_style_test.rb → test_document_style.rb} +1 -1
  40. data/test/{font_test.rb → test_font.rb} +2 -2
  41. data/test/{font_table_test.rb → test_font_table.rb} +2 -2
  42. data/test/{footer_node_test.rb → test_footer_node.rb} +1 -1
  43. data/test/{header_node_test.rb → test_header_node.rb} +1 -1
  44. data/test/{image_node_test.rb → test_image_node.rb} +10 -3
  45. data/test/{information_test.rb → test_information.rb} +1 -1
  46. data/test/{node_test.rb → test_node.rb} +1 -1
  47. data/test/{paragraph_style_test.rb → test_paragraph_style.rb} +1 -1
  48. data/test/{style_test.rb → test_style.rb} +1 -1
  49. data/test/{table_cell_node_test.rb → test_table_cell_node.rb} +1 -1
  50. data/test/{table_node_test.rb → test_table_node.rb} +2 -1
  51. data/test/{table_row_node_test.rb → test_table_row_node.rb} +1 -1
  52. data/test/text_node_test.rb +35 -10
  53. metadata +137 -97
  54. data/CHANGES +0 -23
  55. data/VERSION.yml +0 -5
data/Rakefile CHANGED
@@ -1,40 +1,26 @@
1
+ $:.unshift(File.expand_path(File.dirname(__FILE__)+"/lib"))
1
2
  $:.unshift(File.expand_path(File.dirname(__FILE__)))
2
3
  require 'rake'
3
4
 
4
- begin
5
- require 'jeweler'
6
- Jeweler::Tasks.new do |s|
7
- s.rubyforge_project = "ruby-statsample"
8
- s.name = "clbustos-rtf"
9
- s.summary = 'Ruby library to create rich text format documents.'
10
- s.email = "clbustos@gmail.com"
11
- s.homepage = "http://github.com/clbustos/rtf"
12
- s.description = 'Ruby RTF is a library that can be used to create '\
13
- 'rich text format (RTF) documents. RTF is a text '\
14
- 'based standard for laying out document content.'
15
- s.authors = ["Peter Wood"]
16
- s.files = FileList["[A-Z]*", "{examples,lib,test}/**/*"]
17
- end
18
- rescue LoadError
19
- puts "Jeweler not available. Install it with: sudo gem install jeweler"
20
- end
5
+ require 'rubygems'
6
+ require 'hoe'
7
+ require 'rtf'
8
+ Hoe.plugin :git
21
9
 
22
- require 'rake/rdoctask'
23
- Rake::RDocTask.new do |rdoc|
24
- rdoc.rdoc_dir = 'rdoc'
25
- rdoc.title = 'ruby-rtf'
26
- rdoc.options << '--line-numbers' << '--inline-source'
27
- rdoc.rdoc_files.include('[A-Z]*')
28
- rdoc.rdoc_files.include('lib/**/*.rb')
29
- end
30
10
 
31
- require 'rake/testtask'
32
- Rake::TestTask.new(:test) do |t|
33
- t.libs << 'lib' << 'test'
34
- t.pattern = 'test/**/*_test.rb'
35
- t.verbose = false
11
+ h=Hoe.spec 'clbustos-rtf' do
12
+ # Original author: Peter Wood
13
+ self.developer 'Claudio Bustos', 'clbustos_at_gmail.com'
14
+ self.version=RTF::VERSION
15
+ self.git_log_author=true
16
+ path = File.expand_path("~/.rubyforge/user-config.yml")
17
+ config = YAML.load(File.read(path))
18
+ host = "#{config["username"]}@rubyforge.org"
19
+
20
+ remote_dir = "#{host}:/var/www/gforge-projects/ruby-statsample/rtf"
21
+ self.rdoc_locations << remote_dir
22
+ self.extra_dev_deps << ["hoe",">=0"]
36
23
  end
37
-
38
24
  begin
39
25
  require 'rcov/rcovtask'
40
26
  Rcov::RcovTask.new do |t|
@@ -43,7 +29,5 @@ begin
43
29
  t.verbose = true
44
30
  end
45
31
  rescue LoadError
46
- puts "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
32
+ puts "RCov is not available. In order to run rcov, you must: sudo gem install rcov"
47
33
  end
48
-
49
- task :default => :test
@@ -1,5 +1,9 @@
1
+ # encoding: utf-8
1
2
  #!/usr/bin/env ruby
2
3
 
4
+ $LOAD_PATH.unshift(File.dirname(__FILE__)+"/../lib/")
5
+
6
+
3
7
  require 'rubygems'
4
8
  require 'rtf'
5
9
 
@@ -48,4 +52,4 @@ end
48
52
 
49
53
  File.open('example01.rtf', 'w') do |file|
50
54
  file.write(document.to_rtf)
51
- end
55
+ end
@@ -1,4 +1,5 @@
1
1
  #!/usr/bin/env ruby
2
+ $LOAD_PATH.unshift(File.dirname(__FILE__)+"/../lib/")
2
3
 
3
4
  require 'rubygems'
4
5
  require 'rtf'
@@ -1,4 +1,5 @@
1
1
  #!/usr/bin/env ruby
2
+ $LOAD_PATH.unshift(File.dirname(__FILE__)+"/../lib/")
2
3
 
3
4
  require 'rubygems'
4
5
  require 'rtf'
File without changes
@@ -1,4 +1,5 @@
1
1
  #!/usr/bin/env ruby
2
+ $LOAD_PATH.unshift(File.dirname(__FILE__)+"/../lib/")
2
3
 
3
4
  require 'rubygems'
4
5
  require 'rtf'
File without changes
File without changes
File without changes
@@ -0,0 +1,120 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{ifad-rtf}
8
+ s.version = "0.4.2"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Peter Wood", "Claudio Bustos", "Marcello Barnaba"]
12
+ s.date = %q{2011-06-08}
13
+ s.description = %q{Ruby RTF is a library that can be used to create rich text format (RTF) documents. RTF is a text based standard for laying out document content.}
14
+ s.email = %q{m.barnaba@ifad.org}
15
+ s.extra_rdoc_files = [
16
+ "LICENSE",
17
+ "README.rdoc"
18
+ ]
19
+ s.files = [
20
+ "CHANGES",
21
+ "LICENSE",
22
+ "README.rdoc",
23
+ "Rakefile",
24
+ "VERSION.yml",
25
+ "examples/example01.rb",
26
+ "examples/example02.rb",
27
+ "examples/example03.rb",
28
+ "examples/example03.rtf",
29
+ "examples/example04.rb",
30
+ "examples/rubyrtf.bmp",
31
+ "examples/rubyrtf.jpg",
32
+ "examples/rubyrtf.png",
33
+ "lib/rtf.rb",
34
+ "lib/rtf/colour.rb",
35
+ "lib/rtf/converters.rb",
36
+ "lib/rtf/converters/html.rb",
37
+ "lib/rtf/font.rb",
38
+ "lib/rtf/information.rb",
39
+ "lib/rtf/list.rb",
40
+ "lib/rtf/node.rb",
41
+ "lib/rtf/paper.rb",
42
+ "lib/rtf/style.rb",
43
+ "test/character_style_test.rb",
44
+ "test/colour_table_test.rb",
45
+ "test/colour_test.rb",
46
+ "test/command_node_test.rb",
47
+ "test/container_node_test.rb",
48
+ "test/document_style_test.rb",
49
+ "test/document_test.rb",
50
+ "test/fixtures/bitmap1.bmp",
51
+ "test/fixtures/bitmap2.bmp",
52
+ "test/fixtures/jpeg1.jpg",
53
+ "test/fixtures/jpeg2.jpg",
54
+ "test/fixtures/png1.png",
55
+ "test/fixtures/png2.png",
56
+ "test/font_table_test.rb",
57
+ "test/font_test.rb",
58
+ "test/footer_node_test.rb",
59
+ "test/header_node_test.rb",
60
+ "test/image_node_test.rb",
61
+ "test/information_test.rb",
62
+ "test/node_test.rb",
63
+ "test/paragraph_style_test.rb",
64
+ "test/style_test.rb",
65
+ "test/table_cell_node_test.rb",
66
+ "test/table_node_test.rb",
67
+ "test/table_row_node_test.rb",
68
+ "test/test_helper.rb",
69
+ "test/text_node_test.rb"
70
+ ]
71
+ s.homepage = %q{http://github.com/ifad/rtf}
72
+ s.require_paths = ["lib"]
73
+ s.rubyforge_project = %q{ruby-statsample}
74
+ s.rubygems_version = %q{1.3.7}
75
+ s.summary = %q{Ruby library to create rich text format documents.}
76
+ s.test_files = [
77
+ "examples/example01.rb",
78
+ "examples/example02.rb",
79
+ "examples/example03.rb",
80
+ "examples/example04.rb",
81
+ "test/character_style_test.rb",
82
+ "test/colour_table_test.rb",
83
+ "test/colour_test.rb",
84
+ "test/command_node_test.rb",
85
+ "test/container_node_test.rb",
86
+ "test/document_style_test.rb",
87
+ "test/document_test.rb",
88
+ "test/font_table_test.rb",
89
+ "test/font_test.rb",
90
+ "test/footer_node_test.rb",
91
+ "test/header_node_test.rb",
92
+ "test/image_node_test.rb",
93
+ "test/information_test.rb",
94
+ "test/node_test.rb",
95
+ "test/paragraph_style_test.rb",
96
+ "test/style_test.rb",
97
+ "test/table_cell_node_test.rb",
98
+ "test/table_node_test.rb",
99
+ "test/table_row_node_test.rb",
100
+ "test/test_helper.rb",
101
+ "test/text_node_test.rb"
102
+ ]
103
+
104
+ if s.respond_to? :specification_version then
105
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
106
+ s.specification_version = 3
107
+
108
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
109
+ s.add_runtime_dependency(%q<nokogiri>, ["~> 1.1"])
110
+ s.add_runtime_dependency(%q<tidy-ext>, ["~> 0.1"])
111
+ else
112
+ s.add_dependency(%q<nokogiri>, ["~> 1.1"])
113
+ s.add_dependency(%q<tidy-ext>, ["~> 0.1"])
114
+ end
115
+ else
116
+ s.add_dependency(%q<nokogiri>, ["~> 1.1"])
117
+ s.add_dependency(%q<tidy-ext>, ["~> 0.1"])
118
+ end
119
+ end
120
+
data/lib/rtf.rb CHANGED
@@ -12,6 +12,7 @@ require 'rtf/list'
12
12
  # This module encapsulates all the classes and definitions relating to the RTF
13
13
  # library.
14
14
  module RTF
15
+ VERSION="0.5.0"
15
16
  # This is the exception class used by the RTF library code to indicate
16
17
  # errors.
17
18
  class RTFError < StandardError
File without changes
@@ -0,0 +1,5 @@
1
+ require 'rtf'
2
+ module RTF::Converters
3
+ # Empty, for now
4
+ end
5
+ require 'rtf/converters/html'
@@ -0,0 +1,123 @@
1
+ require 'nokogiri'
2
+ require 'tidy'
3
+
4
+ module RTF::Converters
5
+ class HTML
6
+
7
+ def initialize(html, options = {})
8
+ html = options[:noclean] ? html : clean(html, options[:tidy_options] || {})
9
+ @html = Nokogiri::HTML::Document.parse(html)
10
+ end
11
+
12
+ def to_rtf(options = {})
13
+ to_rtf_document(options).to_rtf
14
+ end
15
+
16
+ def to_rtf_document(options = {})
17
+ font = Helpers.font(options[:font] || :default)
18
+ nodes = NodeSet.new @html.css('body').children
19
+
20
+ RTF::Document.new(font).tap do |rtf|
21
+ nodes.to_rtf(rtf)
22
+ end
23
+ end
24
+
25
+ protected
26
+ def clean(html, options = {})
27
+ defaults = {
28
+ :doctype => 'omit',
29
+ :bare => true,
30
+ :clean => true,
31
+ :drop_empty_paras => true,
32
+ :logical_emphasis => true,
33
+ :lower_literals => true,
34
+ :merge_spans => 1,
35
+ :merge_divs => 1,
36
+ :output_html => true,
37
+ :indent => 0,
38
+ :wrap => 0,
39
+ :char_encoding => 'utf8'
40
+ }
41
+
42
+ tidy = Tidy.new defaults.merge(options)
43
+ tidy.clean(html)
44
+ end
45
+
46
+ module Helpers
47
+ extend self
48
+
49
+ def font(key)
50
+ RTF::Font.new(*case key
51
+ when :default then [RTF::Font::ROMAN, 'Times New Roman']
52
+ when :monospace then [RTF::Font::MODERN, 'Courier New' ]
53
+ end)
54
+ end
55
+
56
+ def style(key)
57
+ RTF::CharacterStyle.new.tap do |style|
58
+ case key.to_sym
59
+ when :h1
60
+ style.font_size = 44
61
+ style.bold = true
62
+ when :h2
63
+ style.font_size = 36
64
+ style.bold = true
65
+ when :h3
66
+ style.font_size = 28
67
+ style.bold = true
68
+ when :h4
69
+ style.font_size = 22
70
+ style.bold = true
71
+ end
72
+ end
73
+ end
74
+ end
75
+
76
+ class NodeSet
77
+ def initialize(nodeset)
78
+ @nodeset = nodeset
79
+ end
80
+
81
+ def to_rtf(rtf)
82
+ @nodeset.each do |node|
83
+ Node.new(node).to_rtf(rtf)
84
+ end
85
+ end
86
+ end
87
+
88
+ class Node # :nodoc:
89
+ def initialize(node)
90
+ @node = node
91
+ end
92
+
93
+ def to_rtf(rtf)
94
+ case @node.name
95
+ when 'text' then rtf << @node.text.gsub(/\n+/, ' ').strip
96
+ when 'br' then rtf.line_break
97
+ when 'b', 'strong' then rtf.bold &recurse
98
+ when 'i', 'em', 'cite' then rtf.italic &recurse
99
+ when 'u' then rtf.underline &recurse
100
+ when 'blockquote', 'p', 'div' then rtf.paragraph &recurse
101
+ when 'span' then recurse.call(rtf)
102
+ when 'sup' then rtf.subscript &recurse
103
+ when 'sub' then rtf.superscript &recurse
104
+ when 'ul' then rtf.list :bullets, &recurse
105
+ when 'ol' then rtf.list :decimal, &recurse
106
+ when 'li' then rtf.item &recurse
107
+ when 'a' then rtf.link @node[:href], &recurse
108
+ when 'h1', 'h2', 'h3', 'h4' then rtf.apply(Helpers.style(@node.name), &recurse); rtf.line_break
109
+ when 'code' then rtf.font Helpers.font(:monospace), &recurse
110
+ else
111
+ #puts "Ignoring #{@node.to_html}"
112
+ end
113
+
114
+ return rtf
115
+ end
116
+
117
+ def recurse
118
+ lambda {|rtf| NodeSet.new(@node.children).to_rtf(rtf)}
119
+ end
120
+ end
121
+
122
+ end
123
+ end
File without changes
File without changes
@@ -115,13 +115,20 @@ module RTF
115
115
  # method escapes any special sequences that appear in the text.
116
116
  def to_rtf
117
117
  rtf=(@text == nil ? '' : @text.gsub("{", "\\{").gsub("}", "\\}").gsub("\\", "\\\\"))
118
+ # This is from lfarcy / rtf-extensions
119
+ # I don't see the point of coding different 128<n<256 range
120
+
121
+ #f1=lambda { |n| n < 128 ? n.chr : n < 256 ? "\\'#{n.to_s(16)}" : "\\u#{n}\\'3f" }
118
122
  # Encode as Unicode.
123
+
124
+ f=lambda { |n| n < 128 ? n.chr : "\\u#{n}\\'3f" }
125
+ # Ruby 1.9 is safe, cause detect original encoding
126
+ # and convert text to utf-16 first
119
127
  if RUBY_VERSION>"1.9.0"
120
- rtf.encode("UTF-16LE").each_codepoint.map {|cp|
121
- cp < 128 ? cp.chr : "\\u#{cp}\\'3f"
122
- }.join("")
128
+ return rtf.encode("UTF-16LE", :undef=>:replace).each_codepoint.map(&f).join('')
123
129
  else
124
- rtf
130
+ # You SHOULD use UTF-8 as input, ok?
131
+ return rtf.unpack('U*').map(&f).join('')
125
132
  end
126
133
  end
127
134
  end # End of the TextNode class.
@@ -701,7 +708,7 @@ module RTF
701
708
  class TableNode < ContainerNode
702
709
  # Cell margin. Default to 100
703
710
  attr_accessor :cell_margin
704
-
711
+
705
712
  # This is a constructor for the TableNode class.
706
713
  #
707
714
  # ==== Parameters
@@ -720,7 +727,7 @@ module RTF
720
727
  rows.times {entries.push(TableRowNode.new(self, columns, *widths))}
721
728
  entries
722
729
  end
723
-
730
+
724
731
  elsif block
725
732
  block.arity<1 ? self.instance_eval(&block) : block.call(self)
726
733
  else
@@ -822,7 +829,7 @@ module RTF
822
829
  text << row.to_rtf
823
830
  end
824
831
 
825
- text.string
832
+ text.string.sub(/\\row(?!.*\\row)/m, "\\lastrow\n\\row")
826
833
  end
827
834
 
828
835
  alias :column_shading_color :column_shading_colour
@@ -933,7 +940,7 @@ module RTF
933
940
  attr_accessor :width
934
941
  # Attribute accessor.
935
942
  attr_reader :shading_colour, :style
936
-
943
+
937
944
  # This is the constructor for the TableCellNode class.
938
945
  #
939
946
  # ==== Parameters
@@ -1261,13 +1268,20 @@ module RTF
1261
1268
  # A definition for an architecture endian constant.
1262
1269
  BIG_ENDIAN = :big
1263
1270
 
1271
+ # Offsets for reading dimension data by filetype
1272
+ DIMENSIONS_OFFSET = {
1273
+ JPEG => 2,
1274
+ PNG => 8,
1275
+ BITMAP => 8,
1276
+ }.freeze
1277
+
1264
1278
  # Attribute accessor.
1265
1279
  attr_reader :x_scaling, :y_scaling, :top_crop, :right_crop, :bottom_crop,
1266
- :left_crop, :width, :height
1280
+ :left_crop, :width, :height, :displayed_width, :displayed_height
1267
1281
 
1268
1282
  # Attribute mutator.
1269
1283
  attr_writer :x_scaling, :y_scaling, :top_crop, :right_crop, :bottom_crop,
1270
- :left_crop
1284
+ :left_crop, :displayed_width, :displayed_height
1271
1285
 
1272
1286
 
1273
1287
  # This is the constructor for the ImageNode class.
@@ -1287,63 +1301,66 @@ module RTF
1287
1301
  super(parent)
1288
1302
  @source = nil
1289
1303
  @id = id
1290
- @read = []
1291
1304
  @type = nil
1292
1305
  @x_scaling = @y_scaling = nil
1293
1306
  @top_crop = @right_crop = @bottom_crop = @left_crop = nil
1294
1307
  @width = @height = nil
1308
+ @displayed_width = @displayed_height = nil
1295
1309
 
1296
- # Check what we were given.
1297
- src = source
1298
- src.binmode if src.instance_of?(File)
1299
- src = File.new(source, 'rb') if source.instance_of?(String)
1300
- if src.instance_of?(File)
1301
- # Check the files existence and accessibility.
1302
- if !File.exist?(src.path)
1303
- RTFError.fire("Unable to find the #{File.basename(source)} file.")
1304
- end
1305
- if !File.readable?(src.path)
1306
- RTFError.fire("Access to the #{File.basename(source)} file denied.")
1307
- end
1308
- @source = src
1309
- else
1310
- RTFError.fire("Unrecognised source specified for ImageNode.")
1310
+ # store path to image
1311
+ @source = source if source.instance_of?(String) || source.instance_of?(Tempfile)
1312
+ @source = source.path if source.instance_of?(File)
1313
+
1314
+ # Check the file's existence and accessibility.
1315
+ if !File.exist?(@source)
1316
+ RTFError.fire("Unable to find the #{File.basename(@source)} file.")
1317
+ end
1318
+ if !File.readable?(@source)
1319
+ RTFError.fire("Access to the #{File.basename(@source)} file denied.")
1311
1320
  end
1312
1321
 
1313
- @type = get_file_type(src)
1322
+ @type = get_file_type
1314
1323
  if @type == nil
1315
- RTFError.fire("The #{File.basename(source)} file contains an "\
1324
+ RTFError.fire("The #{File.basename(@source)} file contains an "\
1316
1325
  "unknown or unsupported image type.")
1317
1326
  end
1318
1327
 
1319
1328
  @width, @height = get_dimensions
1320
1329
  end
1321
1330
 
1331
+ def open_file(&block)
1332
+ if block
1333
+ File.open(@source, 'rb', &block)
1334
+ else
1335
+ File.open(@source, 'rb')
1336
+ end
1337
+ end
1338
+
1322
1339
  # This method attempts to determine the image type associated with a
1323
1340
  # file, returning nil if it fails to make the determination.
1324
- #
1325
- # ==== Parameters
1326
- # file:: A reference to the file to check for image type.
1327
- def get_file_type(file)
1341
+ def get_file_type
1328
1342
  type = nil
1343
+ read = []
1344
+ open_file do |file|
1345
+
1346
+ # Check if the file is a JPEG.
1347
+ read_source(file, read, 2)
1348
+ if read[0,2] == [255, 216]
1349
+ type = JPEG
1350
+ else
1351
+ # Check if it's a PNG.
1352
+ read_source(file, read, 6)
1353
+ if read[0,8] == [137, 80, 78, 71, 13, 10, 26, 10]
1354
+ type = PNG
1355
+ else
1356
+ # Check if its a bitmap.
1357
+ if read[0,2] == [66, 77]
1358
+ size = to_integer(read[2,4])
1359
+ type = BITMAP if size == File.size(@source)
1360
+ end
1361
+ end
1362
+ end
1329
1363
 
1330
- # Check if the file is a JPEG.
1331
- read_source(2)
1332
-
1333
- if @read[0,2] == [255, 216]
1334
- type = JPEG
1335
- else
1336
- # Check if it's a PNG.
1337
- read_source(6)
1338
- if @read[0,8] == [137, 80, 78, 71, 13, 10, 26, 10]
1339
- type = PNG
1340
- else
1341
- # Check if its a bitmap.
1342
- if @read[0,2] == [66, 77]
1343
- size = to_integer(@read[2,4])
1344
- type = BITMAP if size == File.size(file.path)
1345
- end
1346
- end
1347
1364
  end
1348
1365
 
1349
1366
  type
@@ -1351,32 +1368,38 @@ module RTF
1351
1368
 
1352
1369
  # This method generates the RTF for an ImageNode object.
1353
1370
  def to_rtf
1354
- text = StringIO.new
1355
- count = 0
1356
-
1357
- #text << '{\pard{\*\shppict{\pict'
1358
- text << '{\*\shppict{\pict'
1359
- text << "\\picscalex#{@x_scaling}" if @x_scaling != nil
1360
- text << "\\picscaley#{@y_scaling}" if @y_scaling != nil
1361
- text << "\\piccropl#{@left_crop}" if @left_crop != nil
1362
- text << "\\piccropr#{@right_crop}" if @right_crop != nil
1363
- text << "\\piccropt#{@top_crop}" if @top_crop != nil
1364
- text << "\\piccropb#{@bottom_crop}" if @bottom_crop != nil
1365
- text << "\\picw#{@width}\\pich#{@height}\\bliptag#{@id}"
1366
- text << "\\#{@type.id2name}\n"
1367
- @source.each_byte {|byte| @read << byte} if @source.eof? == false
1368
- @read.each do |byte|
1369
- text << ("%02x" % byte)
1371
+ text = StringIO.new
1372
+ count = 0
1373
+
1374
+ #text << '{\pard{\*\shppict{\pict'
1375
+ text << '{\*\shppict{\pict'
1376
+ text << "\\picscalex#{@x_scaling}" if @x_scaling != nil
1377
+ text << "\\picscaley#{@y_scaling}" if @y_scaling != nil
1378
+ text << "\\piccropl#{@left_crop}" if @left_crop != nil
1379
+ text << "\\piccropr#{@right_crop}" if @right_crop != nil
1380
+ text << "\\piccropt#{@top_crop}" if @top_crop != nil
1381
+ text << "\\piccropb#{@bottom_crop}" if @bottom_crop != nil
1382
+ text << "\\picwgoal#{@displayed_width}" if @displayed_width != nil
1383
+ text << "\\pichgoal#{@displayed_height}" if @displayed_height != nil
1384
+ text << "\\picw#{@width}\\pich#{@height}\\bliptag#{@id}"
1385
+ text << "\\#{@type.id2name}\n"
1386
+
1387
+ open_file do |file|
1388
+ file.each_byte do |byte|
1389
+ hex_str = byte.to_s(16)
1390
+ hex_str.insert(0,'0') if hex_str.length == 1
1391
+ text << hex_str
1370
1392
  count += 1
1371
1393
  if count == 40
1372
- text << "\n"
1373
- count = 0
1394
+ text << "\n"
1395
+ count = 0
1374
1396
  end
1375
- end
1376
- #text << "\n}}\\par}"
1377
- text << "\n}}"
1397
+ end
1398
+ end
1399
+ #text << "\n}}\\par}"
1400
+ text << "\n}}"
1378
1401
 
1379
- text.string
1402
+ text.string
1380
1403
  end
1381
1404
 
1382
1405
  # This method is used to determine the underlying endianness of a
@@ -1418,69 +1441,73 @@ module RTF
1418
1441
  # size:: The maximum number of bytes to be read from the file. Defaults
1419
1442
  # to nil to indicate that the remainder of the file should be read
1420
1443
  # in.
1421
- def read_source(size=nil)
1444
+ def read_source(file, read, size=nil)
1422
1445
  if block_given?
1423
1446
  done = false
1424
1447
 
1425
- while done == false && @source.eof? == false
1426
- @read << @source.getbyte
1427
- done = yield @read[-1]
1448
+ while done == false && file.eof? == false
1449
+ read << file.getbyte
1450
+ done = yield read[-1]
1428
1451
  end
1429
1452
  else
1430
1453
  if size != nil
1431
1454
  if size > 0
1432
1455
  total = 0
1433
- while @source.eof? == false && total < size
1434
-
1435
- @read << @source.getbyte
1456
+ while file.eof? == false && total < size
1457
+ read << file.getbyte
1436
1458
  total += 1
1437
1459
  end
1438
1460
  end
1439
1461
  else
1440
- @source.each_byte {|byte| @read << byte}
1462
+ file.each_byte {|byte| read << byte}
1441
1463
  end
1442
1464
  end
1443
1465
  end
1444
1466
 
1467
+
1445
1468
  # This method fetches details of the dimensions associated with an image.
1446
1469
  def get_dimensions
1447
1470
  dimensions = nil
1448
1471
 
1449
- # Check the image type.
1450
- if @type == JPEG
1451
- # Read until we can't anymore or we've found what we're looking for.
1452
- done = false
1453
- while @source.eof? == false && done == false
1454
- # Read to the next marker.
1455
- read_source {|c| c == 0xff} # Read to the marker.
1456
- read_source {|c| c != 0xff} # Skip any padding.
1457
-
1458
- if @read[-1] >= 0xc0 && @read[-1] <= 0xc3
1459
- # Read in the width and height details.
1460
- read_source(7)
1461
- dimensions = @read[-4,4].pack('C4').unpack('nn').reverse
1462
- done = true
1463
- else
1464
- # Skip the marker block.
1465
- read_source(2)
1466
- read_source(@read[-2,2].pack('C2').unpack('n')[0] - 2)
1467
- end
1468
- end
1469
- elsif @type == PNG
1470
- # Read in the data to contain the width and height.
1471
- read_source(16)
1472
- dimensions = @read[-8,8].pack('C8').unpack('N2')
1473
- elsif @type == BITMAP
1474
- # Read in the data to contain the width and height.
1475
- read_source(18)
1476
- dimensions = [to_integer(@read[-8,4]), to_integer(@read[-4,4])]
1472
+ open_file do |file|
1473
+ file.pos = DIMENSIONS_OFFSET[@type]
1474
+ read = []
1475
+
1476
+ # Check the image type.
1477
+ if @type == JPEG
1478
+ # Read until we can't anymore or we've found what we're looking for.
1479
+ done = false
1480
+ while file.eof? == false && done == false
1481
+ # Read to the next marker.
1482
+ read_source(file,read) {|c| c == 0xff} # Read to the marker.
1483
+ read_source(file,read) {|c| c != 0xff} # Skip any padding.
1484
+
1485
+ if read[-1] >= 0xc0 && read[-1] <= 0xc3
1486
+ # Read in the width and height details.
1487
+ read_source(file, read, 7)
1488
+ dimensions = read[-4,4].pack('C4').unpack('nn').reverse
1489
+ done = true
1490
+ else
1491
+ # Skip the marker block.
1492
+ read_source(file, read, 2)
1493
+ read_source(file, read, read[-2,2].pack('C2').unpack('n')[0] - 2)
1494
+ end
1495
+ end
1496
+ elsif @type == PNG
1497
+ # Read in the data to contain the width and height.
1498
+ read_source(file, read, 16)
1499
+ dimensions = read[-8,8].pack('C8').unpack('N2')
1500
+ elsif @type == BITMAP
1501
+ # Read in the data to contain the width and height.
1502
+ read_source(file, read, 18)
1503
+ dimensions = [to_integer(read[-8,4]), to_integer(read[-4,4])]
1504
+ end
1477
1505
  end
1478
1506
 
1479
1507
  dimensions
1480
1508
  end
1481
1509
 
1482
- private :read_source, :get_file_type, :to_integer, :get_endian,
1483
- :get_dimensions
1510
+ private :get_file_type, :to_integer, :get_endian, :get_dimensions, :open_file
1484
1511
  end # End of the ImageNode class.
1485
1512
 
1486
1513