rtf 0.1.0 → 0.3.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.
- data/CHANGES +5 -0
- data/LICENSE +20 -0
- data/{doc/README → README.rdoc} +10 -2
- data/Rakefile +47 -0
- data/VERSION.yml +5 -0
- data/examples/example01.rb +0 -0
- data/examples/example02.rb +0 -0
- data/examples/example03.rb +4 -4
- data/examples/example03.rtf +0 -0
- data/examples/example04.rb +50 -0
- data/examples/rubyrtf.bmp +0 -0
- data/examples/rubyrtf.jpg +0 -0
- data/examples/rubyrtf.png +0 -0
- data/lib/rtf.rb +0 -0
- data/lib/rtf/colour.rb +0 -0
- data/lib/rtf/font.rb +0 -0
- data/lib/rtf/information.rb +2 -3
- data/lib/rtf/node.rb +294 -29
- data/lib/rtf/paper.rb +0 -0
- data/lib/rtf/style.rb +0 -0
- data/test/{CharacterStyleTest.rb → character_style_test.rb} +1 -7
- data/test/{ColourTableTest.rb → colour_table_test.rb} +92 -97
- data/test/{ColourTest.rb → colour_test.rb} +116 -122
- data/test/{CommandNodeTest.rb → command_node_test.rb} +1 -7
- data/test/{ContainerNodeTest.rb → container_node_test.rb} +3 -9
- data/test/{DocumentStyleTest.rb → document_style_test.rb} +1 -7
- data/test/{DocumentTest.rb → document_test.rb} +1 -7
- data/test/fixtures/bitmap1.bmp +0 -0
- data/test/fixtures/bitmap2.bmp +0 -0
- data/test/fixtures/jpeg1.jpg +0 -0
- data/test/fixtures/jpeg2.jpg +0 -0
- data/test/fixtures/png1.png +0 -0
- data/test/fixtures/png2.png +0 -0
- data/test/{FontTableTest.rb → font_table_test.rb} +1 -6
- data/test/{FontTest.rb → font_test.rb} +1 -6
- data/test/{FooterNodeTest.rb → footer_node_test.rb} +1 -7
- data/test/{HeaderNodeTest.rb → header_node_test.rb} +1 -7
- data/test/image_node_test.rb +125 -0
- data/test/{InformationTest.rb → information_test.rb} +1 -7
- data/test/{NodeTest.rb → node_test.rb} +4 -10
- data/test/{ParagraphStyleTest.rb → paragraph_style_test.rb} +1 -7
- data/test/{StyleTest.rb → style_test.rb} +1 -7
- data/test/{TableCellNodeTest.rb → table_cell_node_test.rb} +1 -7
- data/test/{TableNodeTest.rb → table_node_test.rb} +1 -7
- data/test/{TableRowNodeTest.rb → table_row_node_test.rb} +1 -7
- data/test/test_helper.rb +13 -0
- data/test/{TextNodeTest.rb → text_node_test.rb} +4 -10
- metadata +119 -70
- data/doc/makedoc.bat +0 -2
- data/test/run.bat +0 -2
- data/test/unittest.bat +0 -2
- data/test/unittest.rb +0 -21
data/CHANGES
ADDED
@@ -0,0 +1,5 @@
|
|
1
|
+
== CHANGES
|
2
|
+
|
3
|
+
0.3.0
|
4
|
+
* Resolve problems on Ruby 1.9.1 with ImageNode#read_source. Peter uses IO#getc, which returns a String on Ruby 1.9.1, not a Integer, so I replaced with getbyte. [clbustos]
|
5
|
+
* Deleted duplicated definition of ImageNode#style= with attr_writer and def. [clbustos]
|
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009 Peter Wood
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/{doc/README → README.rdoc}
RENAMED
@@ -1,4 +1,4 @@
|
|
1
|
-
== Ruby Rich Text Format (RTF) Library
|
1
|
+
== Ruby Rich Text Format (RTF) Library
|
2
2
|
The RTF library provides a pure Ruby set of functionality that can be used to
|
3
3
|
programmatically create RTF documents. The main aim in developing this library
|
4
4
|
is to ease the complexity involved in assembling RTF documents although some
|
@@ -174,4 +174,12 @@ There you have it. You've been given a quick overview of the basics of using
|
|
174
174
|
the library. For more information consult the HTML based API documentation that
|
175
175
|
is installed with the library gem (if you're reading this you may already be
|
176
176
|
looking at this documentation). Another source of information is the examples
|
177
|
-
directory, so check that out too.
|
177
|
+
directory, so check that out too.
|
178
|
+
|
179
|
+
CONTRIBUTORS
|
180
|
+
|
181
|
+
Claudio Bustos
|
182
|
+
Chris O'Sullivan
|
183
|
+
|
184
|
+
COPYRIGHT
|
185
|
+
Copyright (c) 2009-2011 Peter Wood. See LICENSE for details.
|
data/Rakefile
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'rake'
|
2
|
+
|
3
|
+
begin
|
4
|
+
require 'jeweler'
|
5
|
+
Jeweler::Tasks.new do |s|
|
6
|
+
s.name = "rtf"
|
7
|
+
s.summary = 'Ruby library to create rich text format documents.'
|
8
|
+
s.email = "paw220470@yahoo.ie"
|
9
|
+
s.homepage = "http://github.com/thechrisoshow/rtf"
|
10
|
+
s.description = 'Ruby RTF is a library that can be used to create '\
|
11
|
+
'rich text format (RTF) documents. RTF is a text '\
|
12
|
+
'based standard for laying out document content.'
|
13
|
+
s.authors = ["Peter Wood"]
|
14
|
+
s.files = FileList["[A-Z]*", "{examples,lib,test}/**/*"]
|
15
|
+
end
|
16
|
+
rescue LoadError
|
17
|
+
puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
|
18
|
+
end
|
19
|
+
|
20
|
+
require 'rake/rdoctask'
|
21
|
+
Rake::RDocTask.new do |rdoc|
|
22
|
+
rdoc.rdoc_dir = 'rdoc'
|
23
|
+
rdoc.title = 'ruby-rtf'
|
24
|
+
rdoc.options << '--line-numbers' << '--inline-source'
|
25
|
+
rdoc.rdoc_files.include('[A-Z]*')
|
26
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
27
|
+
end
|
28
|
+
|
29
|
+
require 'rake/testtask'
|
30
|
+
Rake::TestTask.new(:test) do |t|
|
31
|
+
t.libs << 'lib' << 'test'
|
32
|
+
t.pattern = 'test/**/*_test.rb'
|
33
|
+
t.verbose = false
|
34
|
+
end
|
35
|
+
|
36
|
+
begin
|
37
|
+
require 'rcov/rcovtask'
|
38
|
+
Rcov::RcovTask.new do |t|
|
39
|
+
t.libs << 'test'
|
40
|
+
t.test_files = FileList['test/**/*_test.rb']
|
41
|
+
t.verbose = true
|
42
|
+
end
|
43
|
+
rescue LoadError
|
44
|
+
puts "RCov is not available. In order to run rcov, you must: sudo gem install rcov"
|
45
|
+
end
|
46
|
+
|
47
|
+
task :default => :test
|
data/VERSION.yml
ADDED
data/examples/example01.rb
CHANGED
File without changes
|
data/examples/example02.rb
CHANGED
File without changes
|
data/examples/example03.rb
CHANGED
@@ -32,9 +32,9 @@ end
|
|
32
32
|
|
33
33
|
document.paragraph(styles['PS_NORMAL']) do |p1|
|
34
34
|
p1 << 'This document is automatically generated using the RTF Ruby '
|
35
|
-
p1 << 'library
|
36
|
-
p1 << '
|
37
|
-
p1 << '
|
35
|
+
p1 << 'library. This serves as an example of what can be achieved '
|
36
|
+
p1 << 'in document creation via the library. The source code that '
|
37
|
+
p1 << 'was used to generate it is listed below...'
|
38
38
|
end
|
39
39
|
|
40
40
|
document.paragraph(styles['PS_INDENTED']) do |p1|
|
@@ -60,7 +60,7 @@ end
|
|
60
60
|
document.paragraph(styles['PS_NORMAL']) do |p1|
|
61
61
|
p1 << "This example shows the creation of a new document and the "
|
62
62
|
p1 << "of textual content to it. The example also provides examples "
|
63
|
-
p1 << "of using block scope to delimit style scope (lines
|
63
|
+
p1 << "of using block scope to delimit style scope (lines 40-51)."
|
64
64
|
end
|
65
65
|
|
66
66
|
File.open('example03.rtf', 'w') {|file| file.write(document.to_rtf)}
|
data/examples/example03.rtf
CHANGED
File without changes
|
@@ -0,0 +1,50 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'rtf'
|
5
|
+
|
6
|
+
include RTF
|
7
|
+
|
8
|
+
IMAGE_FILE = 'rubyrtf.png'
|
9
|
+
|
10
|
+
begin
|
11
|
+
document = Document.new(Font.new(Font::ROMAN, 'Times New Roman'))
|
12
|
+
|
13
|
+
# Add some text to the document and then add the scaled image.
|
14
|
+
document.paragraph do |p|
|
15
|
+
p << "This is a simple document that attempts to demonstrate the use "
|
16
|
+
p << "of images in a document. A simple image should appear in the page "
|
17
|
+
p << "header above, on the right hand side. The same image, scaled to "
|
18
|
+
p << "four times its normal size, should appear below this text."
|
19
|
+
p.line_break
|
20
|
+
end
|
21
|
+
|
22
|
+
# Add the scaled image.
|
23
|
+
image = document.image(IMAGE_FILE)
|
24
|
+
image.x_scaling = 400
|
25
|
+
image.y_scaling = 400
|
26
|
+
|
27
|
+
# Add some follow up text.
|
28
|
+
document.paragraph do |p|
|
29
|
+
p.line_break
|
30
|
+
p << "Due to the way images are stored in RTF documents, adding images "
|
31
|
+
p << "to a document can result in the document file becoming very large. "
|
32
|
+
p << "The Ruby RTF library supports the addition of images in the PNG, "
|
33
|
+
p << "JPEG and Windows device independent bitmap formats. A compressed "
|
34
|
+
p << "image format (like PNG or JPEG) is preferrable to the plain bitmap "
|
35
|
+
p << "format as this will result in a smaller document file."
|
36
|
+
end
|
37
|
+
|
38
|
+
# Add a header to the document.
|
39
|
+
style = ParagraphStyle.new
|
40
|
+
style.justification = ParagraphStyle::RIGHT_JUSTIFY
|
41
|
+
header = HeaderNode.new(document)
|
42
|
+
header.paragraph(style) {|n| n.image(IMAGE_FILE)}
|
43
|
+
document.header = header
|
44
|
+
|
45
|
+
# Write the document to a file.
|
46
|
+
File.open('example04.rtf', 'w') {|file| file.write(document.to_rtf)}
|
47
|
+
rescue => error
|
48
|
+
puts "ERROR: #{error.message}"
|
49
|
+
error.backtrace.each {|step| puts " #{step}"}
|
50
|
+
end
|
Binary file
|
Binary file
|
Binary file
|
data/lib/rtf.rb
CHANGED
File without changes
|
data/lib/rtf/colour.rb
CHANGED
File without changes
|
data/lib/rtf/font.rb
CHANGED
File without changes
|
data/lib/rtf/information.rb
CHANGED
@@ -1,8 +1,7 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
3
|
require 'stringio'
|
4
|
-
require '
|
5
|
-
|
4
|
+
require 'date'
|
6
5
|
module RTF
|
7
6
|
# This class represents an information group for a RTF document.
|
8
7
|
class Information
|
@@ -56,7 +55,7 @@ module RTF
|
|
56
55
|
if setting.instance_of?(Time)
|
57
56
|
@created = setting
|
58
57
|
else
|
59
|
-
|
58
|
+
datetime = Date._parse(setting.to_s).values_at(:year, :mon, :mday, :hour, :min, :sec, :zone, :wday)
|
60
59
|
if datetime == nil
|
61
60
|
RTFError.fire("Invalid document creation date/time information "\
|
62
61
|
"specified.")
|
data/lib/rtf/node.rb
CHANGED
@@ -63,11 +63,8 @@ module RTF
|
|
63
63
|
# This class represents a specialisation of the Node class to refer to a Node
|
64
64
|
# that simply contains text.
|
65
65
|
class TextNode < Node
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
# Attribute mutator.
|
70
|
-
attr_writer :text
|
66
|
+
# Actual text
|
67
|
+
attr_accessor :text
|
71
68
|
|
72
69
|
# This is the constructor for the TextNode class.
|
73
70
|
#
|
@@ -131,11 +128,8 @@ module RTF
|
|
131
128
|
class ContainerNode < Node
|
132
129
|
include Enumerable
|
133
130
|
|
134
|
-
#
|
135
|
-
|
136
|
-
|
137
|
-
# Attribute mutator.
|
138
|
-
attr_writer :children
|
131
|
+
# Children elements of the node
|
132
|
+
attr_accessor :children
|
139
133
|
|
140
134
|
# This is the constructor for the ContainerNode class.
|
141
135
|
#
|
@@ -208,11 +202,14 @@ module RTF
|
|
208
202
|
# is concrete enough to be used on its own but will also be used as the
|
209
203
|
# base class for some specific command node types.
|
210
204
|
class CommandNode < ContainerNode
|
211
|
-
#
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
205
|
+
# String containing the prefix text for the command
|
206
|
+
attr_accessor :prefix
|
207
|
+
# String containing the suffix text for the command
|
208
|
+
attr_accessor :suffix
|
209
|
+
# A boolean to indicate whether the prefix and suffix should
|
210
|
+
# be written to separate lines whether the node is converted
|
211
|
+
# to RTF. Defaults to true
|
212
|
+
attr_accessor :split
|
216
213
|
|
217
214
|
# This is the constructor for the CommandNode class.
|
218
215
|
#
|
@@ -306,6 +303,19 @@ module RTF
|
|
306
303
|
end
|
307
304
|
end
|
308
305
|
|
306
|
+
# This method inserts a new image at the current position in a node.
|
307
|
+
#
|
308
|
+
# ==== Parameters
|
309
|
+
# source:: Either a string containing the path and name of a file or a
|
310
|
+
# File object for the image file to be inserted.
|
311
|
+
#
|
312
|
+
# ==== Exceptions
|
313
|
+
# RTFError:: Generated whenever an invalid or inaccessible file is
|
314
|
+
# specified or the image file type is not supported.
|
315
|
+
def image(source)
|
316
|
+
self.store(ImageNode.new(self, source, root.get_id))
|
317
|
+
end
|
318
|
+
|
309
319
|
# This method provides a short cut means for applying multiple styles via
|
310
320
|
# single command node. The method accepts a block that will be passed a
|
311
321
|
# reference to the node created. Once the block is complete the new node
|
@@ -509,12 +519,9 @@ module RTF
|
|
509
519
|
# specialised container nodes that contain only TableRowNodes and have their
|
510
520
|
# size specified when they are created an cannot be resized after that.
|
511
521
|
class TableNode < ContainerNode
|
512
|
-
#
|
513
|
-
|
514
|
-
|
515
|
-
# Attribute mutator.
|
516
|
-
attr_writer :cell_margin
|
517
|
-
|
522
|
+
# Cell margin. Default to 100
|
523
|
+
attr_accessor :cell_margin
|
524
|
+
|
518
525
|
# This is a constructor for the TableNode class.
|
519
526
|
#
|
520
527
|
# ==== Parameters
|
@@ -523,12 +530,22 @@ module RTF
|
|
523
530
|
# columns:: The number of columns in the table.
|
524
531
|
# *widths:: One or more integers specifying the widths of the table
|
525
532
|
# columns.
|
526
|
-
def initialize(parent,
|
533
|
+
def initialize(parent, *args, &block)
|
534
|
+
if args.size>=2
|
535
|
+
rows=args.shift
|
536
|
+
columns=args.shift
|
537
|
+
widths=args
|
527
538
|
super(parent) do
|
528
539
|
entries = []
|
529
540
|
rows.times {entries.push(TableRowNode.new(self, columns, *widths))}
|
530
541
|
entries
|
531
542
|
end
|
543
|
+
|
544
|
+
elsif block
|
545
|
+
block.arity<1 ? self.instance_eval(&block) : block.call(self)
|
546
|
+
else
|
547
|
+
raise "You should use 0 or >2 args"
|
548
|
+
end
|
532
549
|
@cell_margin = 100
|
533
550
|
end
|
534
551
|
|
@@ -656,7 +673,7 @@ module RTF
|
|
656
673
|
end
|
657
674
|
end
|
658
675
|
|
659
|
-
#
|
676
|
+
# Attribute accessors
|
660
677
|
def length
|
661
678
|
entries.size
|
662
679
|
end
|
@@ -732,13 +749,11 @@ module RTF
|
|
732
749
|
class TableCellNode < CommandNode
|
733
750
|
# A definition for the default width for the cell.
|
734
751
|
DEFAULT_WIDTH = 300
|
735
|
-
|
752
|
+
# Width of cell
|
753
|
+
attr_accessor :width
|
736
754
|
# Attribute accessor.
|
737
|
-
attr_reader :
|
738
|
-
|
739
|
-
# Attribute mutator.
|
740
|
-
attr_writer :width, :style
|
741
|
-
|
755
|
+
attr_reader :shading_colour, :style
|
756
|
+
|
742
757
|
# This is the constructor for the TableCellNode class.
|
743
758
|
#
|
744
759
|
# ==== Parameters
|
@@ -1058,6 +1073,248 @@ module RTF
|
|
1058
1073
|
end # End of the FooterNode class.
|
1059
1074
|
|
1060
1075
|
|
1076
|
+
# This class represents an image within a RTF document. Currently only the
|
1077
|
+
# PNG, JPEG and Windows Bitmap formats are supported. Efforts are made to
|
1078
|
+
# identify the file type but these are not guaranteed to work.
|
1079
|
+
class ImageNode < Node
|
1080
|
+
# A definition for an image type constant.
|
1081
|
+
PNG = :pngblip
|
1082
|
+
|
1083
|
+
# A definition for an image type constant.
|
1084
|
+
JPEG = :jpegblip
|
1085
|
+
|
1086
|
+
# A definition for an image type constant.
|
1087
|
+
BITMAP = :dibitmap0
|
1088
|
+
|
1089
|
+
# A definition for an architecture endian constant.
|
1090
|
+
LITTLE_ENDIAN = :little
|
1091
|
+
|
1092
|
+
# A definition for an architecture endian constant.
|
1093
|
+
BIG_ENDIAN = :big
|
1094
|
+
|
1095
|
+
# Attribute accessor.
|
1096
|
+
attr_reader :x_scaling, :y_scaling, :top_crop, :right_crop, :bottom_crop,
|
1097
|
+
:left_crop, :width, :height
|
1098
|
+
|
1099
|
+
# Attribute mutator.
|
1100
|
+
attr_writer :x_scaling, :y_scaling, :top_crop, :right_crop, :bottom_crop,
|
1101
|
+
:left_crop
|
1102
|
+
|
1103
|
+
|
1104
|
+
# This is the constructor for the ImageNode class.
|
1105
|
+
#
|
1106
|
+
# ==== Parameters
|
1107
|
+
# parent:: A reference to the node that owns the new image node.
|
1108
|
+
# source:: A reference to the image source. This must be a String or a
|
1109
|
+
# File.
|
1110
|
+
# id:: The unique identifier for the image node.
|
1111
|
+
#
|
1112
|
+
# ==== Exceptions
|
1113
|
+
# RTFError:: Generated whenever the image specified is not recognised as
|
1114
|
+
# a supported image type, something other than a String or
|
1115
|
+
# File or IO is passed as the source parameter or if the
|
1116
|
+
# specified source does not exist or cannot be accessed.
|
1117
|
+
def initialize(parent, source, id)
|
1118
|
+
super(parent)
|
1119
|
+
@source = nil
|
1120
|
+
@id = id
|
1121
|
+
@read = []
|
1122
|
+
@type = nil
|
1123
|
+
@x_scaling = @y_scaling = nil
|
1124
|
+
@top_crop = @right_crop = @bottom_crop = @left_crop = nil
|
1125
|
+
@width = @height = nil
|
1126
|
+
|
1127
|
+
# Check what we were given.
|
1128
|
+
src = source
|
1129
|
+
src.binmode if src.instance_of?(File)
|
1130
|
+
src = File.new(source, 'rb') if source.instance_of?(String)
|
1131
|
+
if src.instance_of?(File)
|
1132
|
+
# Check the files existence and accessibility.
|
1133
|
+
if !File.exist?(src.path)
|
1134
|
+
RTFError.fire("Unable to find the #{File.basename(source)} file.")
|
1135
|
+
end
|
1136
|
+
if !File.readable?(src.path)
|
1137
|
+
RTFError.fire("Access to the #{File.basename(source)} file denied.")
|
1138
|
+
end
|
1139
|
+
@source = src
|
1140
|
+
else
|
1141
|
+
RTFError.fire("Unrecognised source specified for ImageNode.")
|
1142
|
+
end
|
1143
|
+
|
1144
|
+
@type = get_file_type(src)
|
1145
|
+
if @type == nil
|
1146
|
+
RTFError.fire("The #{File.basename(source)} file contains an "\
|
1147
|
+
"unknown or unsupported image type.")
|
1148
|
+
end
|
1149
|
+
|
1150
|
+
@width, @height = get_dimensions
|
1151
|
+
end
|
1152
|
+
|
1153
|
+
# This method attempts to determine the image type associated with a
|
1154
|
+
# file, returning nil if it fails to make the determination.
|
1155
|
+
#
|
1156
|
+
# ==== Parameters
|
1157
|
+
# file:: A reference to the file to check for image type.
|
1158
|
+
def get_file_type(file)
|
1159
|
+
type = nil
|
1160
|
+
|
1161
|
+
# Check if the file is a JPEG.
|
1162
|
+
read_source(2)
|
1163
|
+
|
1164
|
+
if @read[0,2] == [255, 216]
|
1165
|
+
type = JPEG
|
1166
|
+
else
|
1167
|
+
# Check if it's a PNG.
|
1168
|
+
read_source(6)
|
1169
|
+
if @read[0,8] == [137, 80, 78, 71, 13, 10, 26, 10]
|
1170
|
+
type = PNG
|
1171
|
+
else
|
1172
|
+
# Check if its a bitmap.
|
1173
|
+
if @read[0,2] == [66, 77]
|
1174
|
+
size = to_integer(@read[2,4])
|
1175
|
+
type = BITMAP if size == File.size(file.path)
|
1176
|
+
end
|
1177
|
+
end
|
1178
|
+
end
|
1179
|
+
|
1180
|
+
type
|
1181
|
+
end
|
1182
|
+
|
1183
|
+
# This method generates the RTF for an ImageNode object.
|
1184
|
+
def to_rtf
|
1185
|
+
text = StringIO.new
|
1186
|
+
count = 0
|
1187
|
+
|
1188
|
+
#text << '{\pard{\*\shppict{\pict'
|
1189
|
+
text << '{\*\shppict{\pict'
|
1190
|
+
text << "\\picscalex#{@x_scaling}" if @x_scaling != nil
|
1191
|
+
text << "\\picscaley#{@y_scaling}" if @y_scaling != nil
|
1192
|
+
text << "\\piccropl#{@left_crop}" if @left_crop != nil
|
1193
|
+
text << "\\piccropr#{@right_crop}" if @right_crop != nil
|
1194
|
+
text << "\\piccropt#{@top_crop}" if @top_crop != nil
|
1195
|
+
text << "\\piccropb#{@bottom_crop}" if @bottom_crop != nil
|
1196
|
+
text << "\\picw#{@width}\\pich#{@height}\\bliptag#{@id}"
|
1197
|
+
text << "\\#{@type.id2name}\n"
|
1198
|
+
@source.each_byte {|byte| @read << byte} if @source.eof? == false
|
1199
|
+
@read.each do |byte|
|
1200
|
+
text << ("%02x" % byte)
|
1201
|
+
count += 1
|
1202
|
+
if count == 40
|
1203
|
+
text << "\n"
|
1204
|
+
count = 0
|
1205
|
+
end
|
1206
|
+
end
|
1207
|
+
#text << "\n}}\\par}"
|
1208
|
+
text << "\n}}"
|
1209
|
+
|
1210
|
+
text.string
|
1211
|
+
end
|
1212
|
+
|
1213
|
+
# This method is used to determine the underlying endianness of a
|
1214
|
+
# platform.
|
1215
|
+
def get_endian
|
1216
|
+
[0, 125].pack('c2').unpack('s') == [125] ? BIG_ENDIAN : LITTLE_ENDIAN
|
1217
|
+
end
|
1218
|
+
|
1219
|
+
# This method converts an array to an integer. The array must be either
|
1220
|
+
# two or four bytes in length.
|
1221
|
+
#
|
1222
|
+
# ==== Parameters
|
1223
|
+
# array:: A reference to the array containing the data to be converted.
|
1224
|
+
# signed:: A boolean to indicate whether the value is signed. Defaults
|
1225
|
+
# to false.
|
1226
|
+
def to_integer(array, signed=false)
|
1227
|
+
from = nil
|
1228
|
+
to = nil
|
1229
|
+
data = []
|
1230
|
+
|
1231
|
+
if array.size == 2
|
1232
|
+
data.concat(get_endian == BIG_ENDIAN ? array.reverse : array)
|
1233
|
+
from = 'C2'
|
1234
|
+
to = signed ? 's' : 'S'
|
1235
|
+
else
|
1236
|
+
data.concat(get_endian == BIG_ENDIAN ? array[0,4].reverse : array)
|
1237
|
+
from = 'C4'
|
1238
|
+
to = signed ? 'l' : 'L'
|
1239
|
+
end
|
1240
|
+
data.pack(from).unpack(to)[0]
|
1241
|
+
end
|
1242
|
+
|
1243
|
+
# This method loads the data for an image from its source. The method
|
1244
|
+
# accepts two call approaches. If called without a block then the method
|
1245
|
+
# considers the size parameter it is passed. If called with a block the
|
1246
|
+
# method executes until the block returns true.
|
1247
|
+
#
|
1248
|
+
# ==== Parameters
|
1249
|
+
# size:: The maximum number of bytes to be read from the file. Defaults
|
1250
|
+
# to nil to indicate that the remainder of the file should be read
|
1251
|
+
# in.
|
1252
|
+
def read_source(size=nil)
|
1253
|
+
if block_given?
|
1254
|
+
done = false
|
1255
|
+
|
1256
|
+
while done == false && @source.eof? == false
|
1257
|
+
@read << @source.getbyte
|
1258
|
+
done = yield @read[-1]
|
1259
|
+
end
|
1260
|
+
else
|
1261
|
+
if size != nil
|
1262
|
+
if size > 0
|
1263
|
+
total = 0
|
1264
|
+
while @source.eof? == false && total < size
|
1265
|
+
|
1266
|
+
@read << @source.getbyte
|
1267
|
+
total += 1
|
1268
|
+
end
|
1269
|
+
end
|
1270
|
+
else
|
1271
|
+
@source.each_byte {|byte| @read << byte}
|
1272
|
+
end
|
1273
|
+
end
|
1274
|
+
end
|
1275
|
+
|
1276
|
+
# This method fetches details of the dimensions associated with an image.
|
1277
|
+
def get_dimensions
|
1278
|
+
dimensions = nil
|
1279
|
+
|
1280
|
+
# Check the image type.
|
1281
|
+
if @type == JPEG
|
1282
|
+
# Read until we can't anymore or we've found what we're looking for.
|
1283
|
+
done = false
|
1284
|
+
while @source.eof? == false && done == false
|
1285
|
+
# Read to the next marker.
|
1286
|
+
read_source {|c| c == 0xff} # Read to the marker.
|
1287
|
+
read_source {|c| c != 0xff} # Skip any padding.
|
1288
|
+
|
1289
|
+
if @read[-1] >= 0xc0 && @read[-1] <= 0xc3
|
1290
|
+
# Read in the width and height details.
|
1291
|
+
read_source(7)
|
1292
|
+
dimensions = @read[-4,4].pack('C4').unpack('nn').reverse
|
1293
|
+
done = true
|
1294
|
+
else
|
1295
|
+
# Skip the marker block.
|
1296
|
+
read_source(2)
|
1297
|
+
read_source(@read[-2,2].pack('C2').unpack('n')[0] - 2)
|
1298
|
+
end
|
1299
|
+
end
|
1300
|
+
elsif @type == PNG
|
1301
|
+
# Read in the data to contain the width and height.
|
1302
|
+
read_source(16)
|
1303
|
+
dimensions = @read[-8,8].pack('C8').unpack('N2')
|
1304
|
+
elsif @type == BITMAP
|
1305
|
+
# Read in the data to contain the width and height.
|
1306
|
+
read_source(18)
|
1307
|
+
dimensions = [to_integer(@read[-8,4]), to_integer(@read[-4,4])]
|
1308
|
+
end
|
1309
|
+
|
1310
|
+
dimensions
|
1311
|
+
end
|
1312
|
+
|
1313
|
+
private :read_source, :get_file_type, :to_integer, :get_endian,
|
1314
|
+
:get_dimensions
|
1315
|
+
end # End of the ImageNode class.
|
1316
|
+
|
1317
|
+
|
1061
1318
|
# This class represents an RTF document. In actuality it is just a
|
1062
1319
|
# specialised Node type that cannot be assigned a parent and that holds
|
1063
1320
|
# document font, colour and information tables.
|
@@ -1235,6 +1492,14 @@ module RTF
|
|
1235
1492
|
@style = style == nil ? DocumentStyle.new : style
|
1236
1493
|
@headers = [nil, nil, nil, nil]
|
1237
1494
|
@footers = [nil, nil, nil, nil]
|
1495
|
+
@id = 0
|
1496
|
+
end
|
1497
|
+
|
1498
|
+
# This method provides a method that can be called to generate an
|
1499
|
+
# identifier that is unique within the document.
|
1500
|
+
def get_id
|
1501
|
+
@id += 1
|
1502
|
+
Time.now().strftime('%d%m%y') + @id.to_s
|
1238
1503
|
end
|
1239
1504
|
|
1240
1505
|
# Attribute accessor.
|