clbustos-rtf 0.4.2 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
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