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