##// END OF EJS Templates
improve rmagick feature of rfpdf plugin for PDF inline images (#3261)...
Toshi MARUYAMA -
r7686:6cd33a48159e
parent child
Show More
@@ -1,64 +1,69
1 # The MIT License
1 # The MIT License
2 #
2 #
3 # Permission is hereby granted, free of charge, to any person obtaining a copy
3 # Permission is hereby granted, free of charge, to any person obtaining a copy
4 # of this software and associated documentation files (the "Software"), to deal
4 # of this software and associated documentation files (the "Software"), to deal
5 # in the Software without restriction, including without limitation the rights
5 # in the Software without restriction, including without limitation the rights
6 # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
6 # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 # copies of the Software, and to permit persons to whom the Software is
7 # copies of the Software, and to permit persons to whom the Software is
8 # furnished to do so, subject to the following conditions:
8 # furnished to do so, subject to the following conditions:
9 #
9 #
10 # The above copyright notice and this permission notice shall be included in
10 # The above copyright notice and this permission notice shall be included in
11 # all copies or substantial portions of the Software.
11 # all copies or substantial portions of the Software.
12 #
12 #
13 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
13 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
14 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
15 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
16 # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
17 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
18 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19 # THE SOFTWARE.
19 # THE SOFTWARE.
20 #
20 #
21 # This implements native php methods used by tcpdf, which have had to be
21 # This implements native php methods used by tcpdf, which have had to be
22 # reimplemented within Ruby.
22 # reimplemented within Ruby.
23
23
24 module RFPDF
24 module RFPDF
25
25
26 # http://uk2.php.net/getimagesize
26 # http://uk2.php.net/getimagesize
27 def getimagesize(filename)
27 def getimagesize(filename)
28 image = Magick::ImageList.new(filename)
28 image = Magick::ImageList.new(filename)
29
29
30 out = Hash.new
30 out = Hash.new
31 out[0] = image.columns
31 out[0] = image.columns
32 out[1] = image.rows
32 out[1] = image.rows
33
33
34 # These are actually meant to return integer values But I couldn't seem to find anything saying what those values are.
34 # These are actually meant to return integer values But I couldn't seem to find anything saying what those values are.
35 # So for now they return strings. The only place that uses this at the moment is the parsejpeg method, so I've changed that too.
35 # So for now they return strings. The only place that uses this at the moment is the parsejpeg method, so I've changed that too.
36 case image.mime_type
36 case image.mime_type
37 when "image/gif"
37 when "image/gif"
38 out[2] = "GIF"
38 out[2] = "GIF"
39 when "image/jpeg"
39 when "image/jpeg"
40 out[2] = "JPEG"
40 out[2] = "JPEG"
41 when "image/png"
41 when "image/png"
42 out[2] = "PNG"
42 out[2] = "PNG"
43 when " image/vnd.wap.wbmp"
43 when " image/vnd.wap.wbmp"
44 out[2] = "WBMP"
44 out[2] = "WBMP"
45 when "image/x-xpixmap"
45 when "image/x-xpixmap"
46 out[2] = "XPM"
46 out[2] = "XPM"
47 end
47 end
48 out[3] = "height=\"#{image.rows}\" width=\"#{image.columns}\""
48 out[3] = "height=\"#{image.rows}\" width=\"#{image.columns}\""
49 out['mime'] = image.mime_type
49 out['mime'] = image.mime_type
50
50
51 # This needs work to cover more situations
51 # This needs work to cover more situations
52 # I can't see how to just list the number of channels with ImageMagick / rmagick
52 # I can't see how to just list the number of channels with ImageMagick / rmagick
53 if image.colorspace.to_s == "CMYKColorspace"
53 if image.colorspace.to_s == "CMYKColorspace"
54 out['channels'] = 4
54 out['channels'] = 4
55 elsif image.colorspace.to_s == "RGBColorspace"
55 elsif image.colorspace.to_s == "RGBColorspace"
56 out['channels'] = 3
56 out['channels'] = 3
57 end
57 end
58
58
59 out['bits'] = image.channel_depth
59 out['bits'] = image.channel_depth
60 File.open( TCPDF.k_path_cache + File::basename(filename), 'w'){|f|
61 f.binmode
62 f.print image.to_blob
63 f.close
64 }
60
65
61 out
66 out
62 end
67 end
63
68
64 end
69 end
@@ -1,4275 +1,4332
1 #============================================================+
1 #============================================================+
2 # File name : tcpdf.rb
2 # File name : tcpdf.rb
3 # Begin : 2002-08-03
3 # Begin : 2002-08-03
4 # Last Update : 2007-03-20
4 # Last Update : 2007-03-20
5 # Author : Nicola Asuni
5 # Author : Nicola Asuni
6 # Version : 1.53.0.TC031
6 # Version : 1.53.0.TC031
7 # License : GNU LGPL (http://www.gnu.org/copyleft/lesser.html)
7 # License : GNU LGPL (http://www.gnu.org/copyleft/lesser.html)
8 #
8 #
9 # Description : This is a Ruby class for generating PDF files
9 # Description : This is a Ruby class for generating PDF files
10 # on-the-fly without requiring external
10 # on-the-fly without requiring external
11 # extensions.
11 # extensions.
12 #
12 #
13 # IMPORTANT:
13 # IMPORTANT:
14 # This class is an extension and improvement of the Public Domain
14 # This class is an extension and improvement of the Public Domain
15 # FPDF class by Olivier Plathey (http://www.fpdf.org).
15 # FPDF class by Olivier Plathey (http://www.fpdf.org).
16 #
16 #
17 # Main changes by Nicola Asuni:
17 # Main changes by Nicola Asuni:
18 # Ruby porting;
18 # Ruby porting;
19 # UTF-8 Unicode support;
19 # UTF-8 Unicode support;
20 # code refactoring;
20 # code refactoring;
21 # source code clean up;
21 # source code clean up;
22 # code style and formatting;
22 # code style and formatting;
23 # source code documentation using phpDocumentor (www.phpdoc.org);
23 # source code documentation using phpDocumentor (www.phpdoc.org);
24 # All ISO page formats were included;
24 # All ISO page formats were included;
25 # image scale factor;
25 # image scale factor;
26 # includes methods to parse and printsome XHTML code, supporting the following elements: h1, h2, h3, h4, h5, h6, b, u, i, a, img, p, br, strong, em, font, blockquote, li, ul, ol, hr, td, th, tr, table, sup, sub, small;
26 # includes methods to parse and printsome XHTML code, supporting the following elements: h1, h2, h3, h4, h5, h6, b, u, i, a, img, p, br, strong, em, font, blockquote, li, ul, ol, hr, td, th, tr, table, sup, sub, small;
27 # includes a method to print various barcode formats using an improved version of "Generic Barcode Render Class" by Karim Mribti (http://www.mribti.com/barcode/) (require GD library: http://www.boutell.com/gd/);
27 # includes a method to print various barcode formats using an improved version of "Generic Barcode Render Class" by Karim Mribti (http://www.mribti.com/barcode/) (require GD library: http://www.boutell.com/gd/);
28 # defines standard Header() and Footer() methods.
28 # defines standard Header() and Footer() methods.
29 #
29 #
30 # Ported to Ruby by Ed Moss 2007-08-06
30 # Ported to Ruby by Ed Moss 2007-08-06
31 #
31 #
32 #============================================================+
32 #============================================================+
33
33
34 #
34 #
35 # TCPDF Class.
35 # TCPDF Class.
36 # @package com.tecnick.tcpdf
36 # @package com.tecnick.tcpdf
37 #
37 #
38
38
39 @@version = "1.53.0.TC031"
39 @@version = "1.53.0.TC031"
40 @@fpdf_charwidths = {}
40 @@fpdf_charwidths = {}
41
41
42 PDF_PRODUCER = 'TCPDF via RFPDF 1.53.0.TC031 (http://tcpdf.sourceforge.net)'
42 PDF_PRODUCER = 'TCPDF via RFPDF 1.53.0.TC031 (http://tcpdf.sourceforge.net)'
43
43
44 module TCPDFFontDescriptor
44 module TCPDFFontDescriptor
45 @@descriptors = { 'freesans' => {} }
45 @@descriptors = { 'freesans' => {} }
46 @@font_name = 'freesans'
46 @@font_name = 'freesans'
47
47
48 def self.font(font_name)
48 def self.font(font_name)
49 @@descriptors[font_name.gsub(".rb", "")]
49 @@descriptors[font_name.gsub(".rb", "")]
50 end
50 end
51
51
52 def self.define(font_name = 'freesans')
52 def self.define(font_name = 'freesans')
53 @@descriptors[font_name] ||= {}
53 @@descriptors[font_name] ||= {}
54 yield @@descriptors[font_name]
54 yield @@descriptors[font_name]
55 end
55 end
56 end
56 end
57
57
58 # This is a Ruby class for generating PDF files on-the-fly without requiring external extensions.<br>
58 # This is a Ruby class for generating PDF files on-the-fly without requiring external extensions.<br>
59 # This class is an extension and improvement of the FPDF class by Olivier Plathey (http://www.fpdf.org).<br>
59 # This class is an extension and improvement of the FPDF class by Olivier Plathey (http://www.fpdf.org).<br>
60 # This version contains some changes: [porting to Ruby, support for UTF-8 Unicode, code style and formatting, php documentation (www.phpdoc.org), ISO page formats, minor improvements, image scale factor]<br>
60 # This version contains some changes: [porting to Ruby, support for UTF-8 Unicode, code style and formatting, php documentation (www.phpdoc.org), ISO page formats, minor improvements, image scale factor]<br>
61 # TCPDF project (http://tcpdf.sourceforge.net) is based on the Public Domain FPDF class by Olivier Plathey (http://www.fpdf.org).<br>
61 # TCPDF project (http://tcpdf.sourceforge.net) is based on the Public Domain FPDF class by Olivier Plathey (http://www.fpdf.org).<br>
62 # To add your own TTF fonts please read /fonts/README.TXT
62 # To add your own TTF fonts please read /fonts/README.TXT
63 # @name TCPDF
63 # @name TCPDF
64 # @package com.tecnick.tcpdf
64 # @package com.tecnick.tcpdf
65 # @@version 1.53.0.TC031
65 # @@version 1.53.0.TC031
66 # @author Nicola Asuni
66 # @author Nicola Asuni
67 # @link http://tcpdf.sourceforge.net
67 # @link http://tcpdf.sourceforge.net
68 # @license http://www.gnu.org/copyleft/lesser.html LGPL
68 # @license http://www.gnu.org/copyleft/lesser.html LGPL
69 #
69 #
70 class TCPDF
70 class TCPDF
71 include RFPDF
71 include RFPDF
72 include Core::RFPDF
72 include Core::RFPDF
73 include RFPDF::Math
73 include RFPDF::Math
74
74
75 def logger
75 def logger
76 Rails.logger
76 Rails.logger
77 end
77 end
78
78
79 cattr_accessor :k_cell_height_ratio
79 cattr_accessor :k_cell_height_ratio
80 @@k_cell_height_ratio = 1.25
80 @@k_cell_height_ratio = 1.25
81
81
82 cattr_accessor :k_blank_image
82 cattr_accessor :k_blank_image
83 @@k_blank_image = ""
83 @@k_blank_image = ""
84
84
85 cattr_accessor :k_small_ratio
85 cattr_accessor :k_small_ratio
86 @@k_small_ratio = 2/3.0
86 @@k_small_ratio = 2/3.0
87
87
88 cattr_accessor :k_path_cache
88 cattr_accessor :k_path_cache
89 @@k_path_cache = Rails.root.join('tmp')
89 @@k_path_cache = Rails.root.join('tmp')
90
90
91 cattr_accessor :k_path_url_cache
91 cattr_accessor :k_path_url_cache
92 @@k_path_url_cache = Rails.root.join('tmp')
92 @@k_path_url_cache = Rails.root.join('tmp')
93
93
94 cattr_accessor :decoder
94 cattr_accessor :decoder
95
95
96 attr_accessor :barcode
96 attr_accessor :barcode
97
97
98 attr_accessor :buffer
98 attr_accessor :buffer
99
99
100 attr_accessor :diffs
100 attr_accessor :diffs
101
101
102 attr_accessor :color_flag
102 attr_accessor :color_flag
103
103
104 attr_accessor :default_table_columns
104 attr_accessor :default_table_columns
105
105
106 attr_accessor :max_table_columns
106 attr_accessor :max_table_columns
107
107
108 attr_accessor :default_font
108 attr_accessor :default_font
109
109
110 attr_accessor :draw_color
110 attr_accessor :draw_color
111
111
112 attr_accessor :encoding
112 attr_accessor :encoding
113
113
114 attr_accessor :fill_color
114 attr_accessor :fill_color
115
115
116 attr_accessor :fonts
116 attr_accessor :fonts
117
117
118 attr_accessor :font_family
118 attr_accessor :font_family
119
119
120 attr_accessor :font_files
120 attr_accessor :font_files
121
121
122 cattr_accessor :font_path
122 cattr_accessor :font_path
123
123
124 attr_accessor :font_style
124 attr_accessor :font_style
125
125
126 attr_accessor :font_size_pt
126 attr_accessor :font_size_pt
127
127
128 attr_accessor :header_width
128 attr_accessor :header_width
129
129
130 attr_accessor :header_logo
130 attr_accessor :header_logo
131
131
132 attr_accessor :header_logo_width
132 attr_accessor :header_logo_width
133
133
134 attr_accessor :header_title
134 attr_accessor :header_title
135
135
136 attr_accessor :header_string
136 attr_accessor :header_string
137
137
138 attr_accessor :images
138 attr_accessor :images
139
139
140 attr_accessor :img_scale
140 attr_accessor :img_scale
141
141
142 attr_accessor :in_footer
142 attr_accessor :in_footer
143
143
144 attr_accessor :is_unicode
144 attr_accessor :is_unicode
145
145
146 attr_accessor :lasth
146 attr_accessor :lasth
147
147
148 attr_accessor :links
148 attr_accessor :links
149
149
150 attr_accessor :list_ordered
150 attr_accessor :list_ordered
151
151
152 attr_accessor :list_count
152 attr_accessor :list_count
153
153
154 attr_accessor :li_spacer
154 attr_accessor :li_spacer
155
155
156 attr_accessor :n
156 attr_accessor :n
157
157
158 attr_accessor :offsets
158 attr_accessor :offsets
159
159
160 attr_accessor :orientation_changes
160 attr_accessor :orientation_changes
161
161
162 attr_accessor :page
162 attr_accessor :page
163
163
164 attr_accessor :page_links
164 attr_accessor :page_links
165
165
166 attr_accessor :pages
166 attr_accessor :pages
167
167
168 attr_accessor :pdf_version
168 attr_accessor :pdf_version
169
169
170 attr_accessor :prevfill_color
170 attr_accessor :prevfill_color
171
171
172 attr_accessor :prevtext_color
172 attr_accessor :prevtext_color
173
173
174 attr_accessor :print_header
174 attr_accessor :print_header
175
175
176 attr_accessor :print_footer
176 attr_accessor :print_footer
177
177
178 attr_accessor :state
178 attr_accessor :state
179
179
180 attr_accessor :tableborder
180 attr_accessor :tableborder
181
181
182 attr_accessor :tdbegin
182 attr_accessor :tdbegin
183
183
184 attr_accessor :tdwidth
184 attr_accessor :tdwidth
185
185
186 attr_accessor :tdheight
186 attr_accessor :tdheight
187
187
188 attr_accessor :tdalign
188 attr_accessor :tdalign
189
189
190 attr_accessor :tdfill
190 attr_accessor :tdfill
191
191
192 attr_accessor :tempfontsize
192 attr_accessor :tempfontsize
193
193
194 attr_accessor :text_color
194 attr_accessor :text_color
195
195
196 attr_accessor :underline
196 attr_accessor :underline
197
197
198 attr_accessor :ws
198 attr_accessor :ws
199
199
200 #
200 #
201 # This is the class constructor.
201 # This is the class constructor.
202 # It allows to set up the page format, the orientation and
202 # It allows to set up the page format, the orientation and
203 # the measure unit used in all the methods (except for the font sizes).
203 # the measure unit used in all the methods (except for the font sizes).
204 # @since 1.0
204 # @since 1.0
205 # @param string :orientation page orientation. Possible values are (case insensitive):<ul><li>P or Portrait (default)</li><li>L or Landscape</li></ul>
205 # @param string :orientation page orientation. Possible values are (case insensitive):<ul><li>P or Portrait (default)</li><li>L or Landscape</li></ul>
206 # @param string :unit User measure unit. Possible values are:<ul><li>pt: point</li><li>mm: millimeter (default)</li><li>cm: centimeter</li><li>in: inch</li></ul><br />A point equals 1/72 of inch, that is to say about 0.35 mm (an inch being 2.54 cm). This is a very common unit in typography; font sizes are expressed in that unit.
206 # @param string :unit User measure unit. Possible values are:<ul><li>pt: point</li><li>mm: millimeter (default)</li><li>cm: centimeter</li><li>in: inch</li></ul><br />A point equals 1/72 of inch, that is to say about 0.35 mm (an inch being 2.54 cm). This is a very common unit in typography; font sizes are expressed in that unit.
207 # @param mixed :format The format used for pages. It can be either one of the following values (case insensitive) or a custom format in the form of a two-element array containing the width and the height (expressed in the unit given by unit).<ul><li>4A0</li><li>2A0</li><li>A0</li><li>A1</li><li>A2</li><li>A3</li><li>A4 (default)</li><li>A5</li><li>A6</li><li>A7</li><li>A8</li><li>A9</li><li>A10</li><li>B0</li><li>B1</li><li>B2</li><li>B3</li><li>B4</li><li>B5</li><li>B6</li><li>B7</li><li>B8</li><li>B9</li><li>B10</li><li>C0</li><li>C1</li><li>C2</li><li>C3</li><li>C4</li><li>C5</li><li>C6</li><li>C7</li><li>C8</li><li>C9</li><li>C10</li><li>RA0</li><li>RA1</li><li>RA2</li><li>RA3</li><li>RA4</li><li>SRA0</li><li>SRA1</li><li>SRA2</li><li>SRA3</li><li>SRA4</li><li>LETTER</li><li>LEGAL</li><li>EXECUTIVE</li><li>FOLIO</li></ul>
207 # @param mixed :format The format used for pages. It can be either one of the following values (case insensitive) or a custom format in the form of a two-element array containing the width and the height (expressed in the unit given by unit).<ul><li>4A0</li><li>2A0</li><li>A0</li><li>A1</li><li>A2</li><li>A3</li><li>A4 (default)</li><li>A5</li><li>A6</li><li>A7</li><li>A8</li><li>A9</li><li>A10</li><li>B0</li><li>B1</li><li>B2</li><li>B3</li><li>B4</li><li>B5</li><li>B6</li><li>B7</li><li>B8</li><li>B9</li><li>B10</li><li>C0</li><li>C1</li><li>C2</li><li>C3</li><li>C4</li><li>C5</li><li>C6</li><li>C7</li><li>C8</li><li>C9</li><li>C10</li><li>RA0</li><li>RA1</li><li>RA2</li><li>RA3</li><li>RA4</li><li>SRA0</li><li>SRA1</li><li>SRA2</li><li>SRA3</li><li>SRA4</li><li>LETTER</li><li>LEGAL</li><li>EXECUTIVE</li><li>FOLIO</li></ul>
208 # @param boolean :unicode TRUE means that the input text is unicode (default = true)
208 # @param boolean :unicode TRUE means that the input text is unicode (default = true)
209 # @param String :encoding charset encoding; default is UTF-8
209 # @param String :encoding charset encoding; default is UTF-8
210 #
210 #
211 def initialize(orientation = 'P', unit = 'mm', format = 'A4', unicode = true, encoding = "UTF-8")
211 def initialize(orientation = 'P', unit = 'mm', format = 'A4', unicode = true, encoding = "UTF-8")
212
212
213 # Set internal character encoding to ASCII#
213 # Set internal character encoding to ASCII#
214 #FIXME 2007-05-25 (EJM) Level=0 -
214 #FIXME 2007-05-25 (EJM) Level=0 -
215 # if (respond_to?("mb_internal_encoding") and mb_internal_encoding())
215 # if (respond_to?("mb_internal_encoding") and mb_internal_encoding())
216 # @internal_encoding = mb_internal_encoding();
216 # @internal_encoding = mb_internal_encoding();
217 # mb_internal_encoding("ASCII");
217 # mb_internal_encoding("ASCII");
218 # }
218 # }
219
219
220 #Some checks
220 #Some checks
221 dochecks();
221 dochecks();
222
222
223 begin
223 begin
224 @@decoder = HTMLEntities.new
224 @@decoder = HTMLEntities.new
225 rescue
225 rescue
226 @@decoder = nil
226 @@decoder = nil
227 end
227 end
228
228
229 #Initialization of properties
229 #Initialization of properties
230 @barcode ||= false
230 @barcode ||= false
231 @buffer ||= ''
231 @buffer ||= ''
232 @diffs ||= []
232 @diffs ||= []
233 @color_flag ||= false
233 @color_flag ||= false
234 @default_table_columns ||= 4
234 @default_table_columns ||= 4
235 @table_columns ||= 0
235 @table_columns ||= 0
236 @max_table_columns ||= []
236 @max_table_columns ||= []
237 @tr_id ||= 0
237 @tr_id ||= 0
238 @max_td_page ||= []
238 @max_td_page ||= []
239 @max_td_y ||= []
239 @max_td_y ||= []
240 @t_columns ||= 0
240 @t_columns ||= 0
241 @default_font ||= "FreeSans" if unicode
241 @default_font ||= "FreeSans" if unicode
242 @default_font ||= "Helvetica"
242 @default_font ||= "Helvetica"
243 @draw_color ||= '0 G'
243 @draw_color ||= '0 G'
244 @encoding ||= "UTF-8"
244 @encoding ||= "UTF-8"
245 @fill_color ||= '0 g'
245 @fill_color ||= '0 g'
246 @fonts ||= {}
246 @fonts ||= {}
247 @font_family ||= ''
247 @font_family ||= ''
248 @font_files ||= {}
248 @font_files ||= {}
249 @font_style ||= ''
249 @font_style ||= ''
250 @font_size ||= 12
250 @font_size ||= 12
251 @font_size_pt ||= 12
251 @font_size_pt ||= 12
252 @header_width ||= 0
252 @header_width ||= 0
253 @header_logo ||= ""
253 @header_logo ||= ""
254 @header_logo_width ||= 30
254 @header_logo_width ||= 30
255 @header_title ||= ""
255 @header_title ||= ""
256 @header_string ||= ""
256 @header_string ||= ""
257 @images ||= {}
257 @images ||= {}
258 @img_scale ||= 1
258 @img_scale ||= 1
259 @in_footer ||= false
259 @in_footer ||= false
260 @is_unicode = unicode
260 @is_unicode = unicode
261 @lasth ||= 0
261 @lasth ||= 0
262 @links ||= []
262 @links ||= []
263 @list_ordered ||= []
263 @list_ordered ||= []
264 @list_count ||= []
264 @list_count ||= []
265 @li_spacer ||= ""
265 @li_spacer ||= ""
266 @li_count ||= 0
266 @li_count ||= 0
267 @spacer ||= ""
267 @spacer ||= ""
268 @quote_count ||= 0
268 @quote_count ||= 0
269 @prevquote_count ||= 0
269 @prevquote_count ||= 0
270 @quote_top ||= []
270 @quote_top ||= []
271 @quote_page ||= []
271 @quote_page ||= []
272 @n ||= 2
272 @n ||= 2
273 @offsets ||= []
273 @offsets ||= []
274 @orientation_changes ||= []
274 @orientation_changes ||= []
275 @page ||= 0
275 @page ||= 0
276 @page_links ||= {}
276 @page_links ||= {}
277 @pages ||= []
277 @pages ||= []
278 @pdf_version ||= "1.3"
278 @pdf_version ||= "1.3"
279 @prevfill_color ||= [255,255,255]
279 @prevfill_color ||= [255,255,255]
280 @prevtext_color ||= [0,0,0]
280 @prevtext_color ||= [0,0,0]
281 @print_header ||= false
281 @print_header ||= false
282 @print_footer ||= false
282 @print_footer ||= false
283 @state ||= 0
283 @state ||= 0
284 @tableborder ||= 0
284 @tableborder ||= 0
285 @tdbegin ||= false
285 @tdbegin ||= false
286 @tdwidth ||= 0
286 @tdwidth ||= 0
287 @tdheight ||= 0
287 @tdheight ||= 0
288 @tdalign ||= "L"
288 @tdalign ||= "L"
289 @tdfill ||= 0
289 @tdfill ||= 0
290 @tempfontsize ||= 10
290 @tempfontsize ||= 10
291 @text_color ||= '0 g'
291 @text_color ||= '0 g'
292 @underline ||= false
292 @underline ||= false
293 @deleted ||= false
293 @deleted ||= false
294 @ws ||= 0
294 @ws ||= 0
295
295
296 #Standard Unicode fonts
296 #Standard Unicode fonts
297 @core_fonts = {
297 @core_fonts = {
298 'courier'=>'Courier',
298 'courier'=>'Courier',
299 'courierB'=>'Courier-Bold',
299 'courierB'=>'Courier-Bold',
300 'courierI'=>'Courier-Oblique',
300 'courierI'=>'Courier-Oblique',
301 'courierBI'=>'Courier-BoldOblique',
301 'courierBI'=>'Courier-BoldOblique',
302 'helvetica'=>'Helvetica',
302 'helvetica'=>'Helvetica',
303 'helveticaB'=>'Helvetica-Bold',
303 'helveticaB'=>'Helvetica-Bold',
304 'helveticaI'=>'Helvetica-Oblique',
304 'helveticaI'=>'Helvetica-Oblique',
305 'helveticaBI'=>'Helvetica-BoldOblique',
305 'helveticaBI'=>'Helvetica-BoldOblique',
306 'times'=>'Times-Roman',
306 'times'=>'Times-Roman',
307 'timesB'=>'Times-Bold',
307 'timesB'=>'Times-Bold',
308 'timesI'=>'Times-Italic',
308 'timesI'=>'Times-Italic',
309 'timesBI'=>'Times-BoldItalic',
309 'timesBI'=>'Times-BoldItalic',
310 'symbol'=>'Symbol',
310 'symbol'=>'Symbol',
311 'zapfdingbats'=>'ZapfDingbats'}
311 'zapfdingbats'=>'ZapfDingbats'}
312
312
313 #Scale factor
313 #Scale factor
314 case unit.downcase
314 case unit.downcase
315 when 'pt' ; @k=1
315 when 'pt' ; @k=1
316 when 'mm' ; @k=72/25.4
316 when 'mm' ; @k=72/25.4
317 when 'cm' ; @k=72/2.54
317 when 'cm' ; @k=72/2.54
318 when 'in' ; @k=72
318 when 'in' ; @k=72
319 else Error("Incorrect unit: #{unit}")
319 else Error("Incorrect unit: #{unit}")
320 end
320 end
321
321
322 #Page format
322 #Page format
323 if format.is_a?(String)
323 if format.is_a?(String)
324 # Page formats (45 standard ISO paper formats and 4 american common formats).
324 # Page formats (45 standard ISO paper formats and 4 american common formats).
325 # Paper cordinates are calculated in this way: (inches# 72) where (1 inch = 2.54 cm)
325 # Paper cordinates are calculated in this way: (inches# 72) where (1 inch = 2.54 cm)
326 case (format.upcase)
326 case (format.upcase)
327 when '4A0' ; format = [4767.87,6740.79]
327 when '4A0' ; format = [4767.87,6740.79]
328 when '2A0' ; format = [3370.39,4767.87]
328 when '2A0' ; format = [3370.39,4767.87]
329 when 'A0' ; format = [2383.94,3370.39]
329 when 'A0' ; format = [2383.94,3370.39]
330 when 'A1' ; format = [1683.78,2383.94]
330 when 'A1' ; format = [1683.78,2383.94]
331 when 'A2' ; format = [1190.55,1683.78]
331 when 'A2' ; format = [1190.55,1683.78]
332 when 'A3' ; format = [841.89,1190.55]
332 when 'A3' ; format = [841.89,1190.55]
333 when 'A4' ; format = [595.28,841.89] # ; default
333 when 'A4' ; format = [595.28,841.89] # ; default
334 when 'A5' ; format = [419.53,595.28]
334 when 'A5' ; format = [419.53,595.28]
335 when 'A6' ; format = [297.64,419.53]
335 when 'A6' ; format = [297.64,419.53]
336 when 'A7' ; format = [209.76,297.64]
336 when 'A7' ; format = [209.76,297.64]
337 when 'A8' ; format = [147.40,209.76]
337 when 'A8' ; format = [147.40,209.76]
338 when 'A9' ; format = [104.88,147.40]
338 when 'A9' ; format = [104.88,147.40]
339 when 'A10' ; format = [73.70,104.88]
339 when 'A10' ; format = [73.70,104.88]
340 when 'B0' ; format = [2834.65,4008.19]
340 when 'B0' ; format = [2834.65,4008.19]
341 when 'B1' ; format = [2004.09,2834.65]
341 when 'B1' ; format = [2004.09,2834.65]
342 when 'B2' ; format = [1417.32,2004.09]
342 when 'B2' ; format = [1417.32,2004.09]
343 when 'B3' ; format = [1000.63,1417.32]
343 when 'B3' ; format = [1000.63,1417.32]
344 when 'B4' ; format = [708.66,1000.63]
344 when 'B4' ; format = [708.66,1000.63]
345 when 'B5' ; format = [498.90,708.66]
345 when 'B5' ; format = [498.90,708.66]
346 when 'B6' ; format = [354.33,498.90]
346 when 'B6' ; format = [354.33,498.90]
347 when 'B7' ; format = [249.45,354.33]
347 when 'B7' ; format = [249.45,354.33]
348 when 'B8' ; format = [175.75,249.45]
348 when 'B8' ; format = [175.75,249.45]
349 when 'B9' ; format = [124.72,175.75]
349 when 'B9' ; format = [124.72,175.75]
350 when 'B10' ; format = [87.87,124.72]
350 when 'B10' ; format = [87.87,124.72]
351 when 'C0' ; format = [2599.37,3676.54]
351 when 'C0' ; format = [2599.37,3676.54]
352 when 'C1' ; format = [1836.85,2599.37]
352 when 'C1' ; format = [1836.85,2599.37]
353 when 'C2' ; format = [1298.27,1836.85]
353 when 'C2' ; format = [1298.27,1836.85]
354 when 'C3' ; format = [918.43,1298.27]
354 when 'C3' ; format = [918.43,1298.27]
355 when 'C4' ; format = [649.13,918.43]
355 when 'C4' ; format = [649.13,918.43]
356 when 'C5' ; format = [459.21,649.13]
356 when 'C5' ; format = [459.21,649.13]
357 when 'C6' ; format = [323.15,459.21]
357 when 'C6' ; format = [323.15,459.21]
358 when 'C7' ; format = [229.61,323.15]
358 when 'C7' ; format = [229.61,323.15]
359 when 'C8' ; format = [161.57,229.61]
359 when 'C8' ; format = [161.57,229.61]
360 when 'C9' ; format = [113.39,161.57]
360 when 'C9' ; format = [113.39,161.57]
361 when 'C10' ; format = [79.37,113.39]
361 when 'C10' ; format = [79.37,113.39]
362 when 'RA0' ; format = [2437.80,3458.27]
362 when 'RA0' ; format = [2437.80,3458.27]
363 when 'RA1' ; format = [1729.13,2437.80]
363 when 'RA1' ; format = [1729.13,2437.80]
364 when 'RA2' ; format = [1218.90,1729.13]
364 when 'RA2' ; format = [1218.90,1729.13]
365 when 'RA3' ; format = [864.57,1218.90]
365 when 'RA3' ; format = [864.57,1218.90]
366 when 'RA4' ; format = [609.45,864.57]
366 when 'RA4' ; format = [609.45,864.57]
367 when 'SRA0' ; format = [2551.18,3628.35]
367 when 'SRA0' ; format = [2551.18,3628.35]
368 when 'SRA1' ; format = [1814.17,2551.18]
368 when 'SRA1' ; format = [1814.17,2551.18]
369 when 'SRA2' ; format = [1275.59,1814.17]
369 when 'SRA2' ; format = [1275.59,1814.17]
370 when 'SRA3' ; format = [907.09,1275.59]
370 when 'SRA3' ; format = [907.09,1275.59]
371 when 'SRA4' ; format = [637.80,907.09]
371 when 'SRA4' ; format = [637.80,907.09]
372 when 'LETTER' ; format = [612.00,792.00]
372 when 'LETTER' ; format = [612.00,792.00]
373 when 'LEGAL' ; format = [612.00,1008.00]
373 when 'LEGAL' ; format = [612.00,1008.00]
374 when 'EXECUTIVE' ; format = [521.86,756.00]
374 when 'EXECUTIVE' ; format = [521.86,756.00]
375 when 'FOLIO' ; format = [612.00,936.00]
375 when 'FOLIO' ; format = [612.00,936.00]
376 #else then Error("Unknown page format: #{format}"
376 #else then Error("Unknown page format: #{format}"
377 end
377 end
378 @fw_pt = format[0]
378 @fw_pt = format[0]
379 @fh_pt = format[1]
379 @fh_pt = format[1]
380 else
380 else
381 @fw_pt = format[0]*@k
381 @fw_pt = format[0]*@k
382 @fh_pt = format[1]*@k
382 @fh_pt = format[1]*@k
383 end
383 end
384
384
385 @fw = @fw_pt/@k
385 @fw = @fw_pt/@k
386 @fh = @fh_pt/@k
386 @fh = @fh_pt/@k
387
387
388 #Page orientation
388 #Page orientation
389 orientation = orientation.downcase
389 orientation = orientation.downcase
390 if orientation == 'p' or orientation == 'portrait'
390 if orientation == 'p' or orientation == 'portrait'
391 @def_orientation = 'P'
391 @def_orientation = 'P'
392 @w_pt = @fw_pt
392 @w_pt = @fw_pt
393 @h_pt = @fh_pt
393 @h_pt = @fh_pt
394 elsif orientation == 'l' or orientation == 'landscape'
394 elsif orientation == 'l' or orientation == 'landscape'
395 @def_orientation = 'L'
395 @def_orientation = 'L'
396 @w_pt = @fh_pt
396 @w_pt = @fh_pt
397 @h_pt = @fw_pt
397 @h_pt = @fw_pt
398 else
398 else
399 Error("Incorrect orientation: #{orientation}")
399 Error("Incorrect orientation: #{orientation}")
400 end
400 end
401
401
402 @cur_orientation = @def_orientation
402 @cur_orientation = @def_orientation
403 @w = @w_pt/@k
403 @w = @w_pt/@k
404 @h = @h_pt/@k
404 @h = @h_pt/@k
405 #Page margins (1 cm)
405 #Page margins (1 cm)
406 margin = 28.35/@k
406 margin = 28.35/@k
407 SetMargins(margin, margin)
407 SetMargins(margin, margin)
408 #Interior cell margin (1 mm)
408 #Interior cell margin (1 mm)
409 @c_margin = margin / 10
409 @c_margin = margin / 10
410 #Line width (0.2 mm)
410 #Line width (0.2 mm)
411 @line_width = 0.567 / @k
411 @line_width = 0.567 / @k
412 #Automatic page break
412 #Automatic page break
413 SetAutoPageBreak(true, 2 * margin)
413 SetAutoPageBreak(true, 2 * margin)
414 #Full width display mode
414 #Full width display mode
415 SetDisplayMode('fullwidth')
415 SetDisplayMode('fullwidth')
416 #Compression
416 #Compression
417 SetCompression(true)
417 SetCompression(true)
418 #Set default PDF version number
418 #Set default PDF version number
419 @pdf_version = "1.3"
419 @pdf_version = "1.3"
420
420
421 @encoding = encoding
421 @encoding = encoding
422 @b = 0
422 @b = 0
423 @i = 0
423 @i = 0
424 @u = 0
424 @u = 0
425 @href = ''
425 @href = ''
426 @fontlist = ["arial", "times", "courier", "helvetica", "symbol"]
426 @fontlist = ["arial", "times", "courier", "helvetica", "symbol"]
427 @issetfont = false
427 @issetfont = false
428 @issetcolor = false
428 @issetcolor = false
429
429
430 SetFillColor(200, 200, 200, true)
430 SetFillColor(200, 200, 200, true)
431 SetTextColor(0, 0, 0, true)
431 SetTextColor(0, 0, 0, true)
432 end
432 end
433
433
434 #
434 #
435 # Set the image scale.
435 # Set the image scale.
436 # @param float :scale image scale.
436 # @param float :scale image scale.
437 # @author Nicola Asuni
437 # @author Nicola Asuni
438 # @since 1.5.2
438 # @since 1.5.2
439 #
439 #
440 def SetImageScale(scale)
440 def SetImageScale(scale)
441 @img_scale = scale;
441 @img_scale = scale;
442 end
442 end
443 alias_method :set_image_scale, :SetImageScale
443 alias_method :set_image_scale, :SetImageScale
444
444
445 #
445 #
446 # Returns the image scale.
446 # Returns the image scale.
447 # @return float image scale.
447 # @return float image scale.
448 # @author Nicola Asuni
448 # @author Nicola Asuni
449 # @since 1.5.2
449 # @since 1.5.2
450 #
450 #
451 def GetImageScale()
451 def GetImageScale()
452 return @img_scale;
452 return @img_scale;
453 end
453 end
454 alias_method :get_image_scale, :GetImageScale
454 alias_method :get_image_scale, :GetImageScale
455
455
456 #
456 #
457 # Returns the page width in units.
457 # Returns the page width in units.
458 # @return int page width.
458 # @return int page width.
459 # @author Nicola Asuni
459 # @author Nicola Asuni
460 # @since 1.5.2
460 # @since 1.5.2
461 #
461 #
462 def GetPageWidth()
462 def GetPageWidth()
463 return @w;
463 return @w;
464 end
464 end
465 alias_method :get_page_width, :GetPageWidth
465 alias_method :get_page_width, :GetPageWidth
466
466
467 #
467 #
468 # Returns the page height in units.
468 # Returns the page height in units.
469 # @return int page height.
469 # @return int page height.
470 # @author Nicola Asuni
470 # @author Nicola Asuni
471 # @since 1.5.2
471 # @since 1.5.2
472 #
472 #
473 def GetPageHeight()
473 def GetPageHeight()
474 return @h;
474 return @h;
475 end
475 end
476 alias_method :get_page_height, :GetPageHeight
476 alias_method :get_page_height, :GetPageHeight
477
477
478 #
478 #
479 # Returns the page break margin.
479 # Returns the page break margin.
480 # @return int page break margin.
480 # @return int page break margin.
481 # @author Nicola Asuni
481 # @author Nicola Asuni
482 # @since 1.5.2
482 # @since 1.5.2
483 #
483 #
484 def GetBreakMargin()
484 def GetBreakMargin()
485 return @b_margin;
485 return @b_margin;
486 end
486 end
487 alias_method :get_break_margin, :GetBreakMargin
487 alias_method :get_break_margin, :GetBreakMargin
488
488
489 #
489 #
490 # Returns the scale factor (number of points in user unit).
490 # Returns the scale factor (number of points in user unit).
491 # @return int scale factor.
491 # @return int scale factor.
492 # @author Nicola Asuni
492 # @author Nicola Asuni
493 # @since 1.5.2
493 # @since 1.5.2
494 #
494 #
495 def GetScaleFactor()
495 def GetScaleFactor()
496 return @k;
496 return @k;
497 end
497 end
498 alias_method :get_scale_factor, :GetScaleFactor
498 alias_method :get_scale_factor, :GetScaleFactor
499
499
500 #
500 #
501 # Defines the left, top and right margins. By default, they equal 1 cm. Call this method to change them.
501 # Defines the left, top and right margins. By default, they equal 1 cm. Call this method to change them.
502 # @param float :left Left margin.
502 # @param float :left Left margin.
503 # @param float :top Top margin.
503 # @param float :top Top margin.
504 # @param float :right Right margin. Default value is the left one.
504 # @param float :right Right margin. Default value is the left one.
505 # @since 1.0
505 # @since 1.0
506 # @see SetLeftMargin(), SetTopMargin(), SetRightMargin(), SetAutoPageBreak()
506 # @see SetLeftMargin(), SetTopMargin(), SetRightMargin(), SetAutoPageBreak()
507 #
507 #
508 def SetMargins(left, top, right=-1)
508 def SetMargins(left, top, right=-1)
509 #Set left, top and right margins
509 #Set left, top and right margins
510 @l_margin = left
510 @l_margin = left
511 @t_margin = top
511 @t_margin = top
512 if (right == -1)
512 if (right == -1)
513 right = left
513 right = left
514 end
514 end
515 @r_margin = right
515 @r_margin = right
516 end
516 end
517 alias_method :set_margins, :SetMargins
517 alias_method :set_margins, :SetMargins
518
518
519 #
519 #
520 # Defines the left margin. The method can be called before creating the first page. If the current abscissa gets out of page, it is brought back to the margin.
520 # Defines the left margin. The method can be called before creating the first page. If the current abscissa gets out of page, it is brought back to the margin.
521 # @param float :margin The margin.
521 # @param float :margin The margin.
522 # @since 1.4
522 # @since 1.4
523 # @see SetTopMargin(), SetRightMargin(), SetAutoPageBreak(), SetMargins()
523 # @see SetTopMargin(), SetRightMargin(), SetAutoPageBreak(), SetMargins()
524 #
524 #
525 def SetLeftMargin(margin)
525 def SetLeftMargin(margin)
526 #Set left margin
526 #Set left margin
527 @l_margin = margin
527 @l_margin = margin
528 if ((@page>0) and (@x < margin))
528 if ((@page>0) and (@x < margin))
529 @x = margin
529 @x = margin
530 end
530 end
531 end
531 end
532 alias_method :set_left_margin, :SetLeftMargin
532 alias_method :set_left_margin, :SetLeftMargin
533
533
534 #
534 #
535 # Defines the top margin. The method can be called before creating the first page.
535 # Defines the top margin. The method can be called before creating the first page.
536 # @param float :margin The margin.
536 # @param float :margin The margin.
537 # @since 1.5
537 # @since 1.5
538 # @see SetLeftMargin(), SetRightMargin(), SetAutoPageBreak(), SetMargins()
538 # @see SetLeftMargin(), SetRightMargin(), SetAutoPageBreak(), SetMargins()
539 #
539 #
540 def SetTopMargin(margin)
540 def SetTopMargin(margin)
541 #Set top margin
541 #Set top margin
542 @t_margin = margin
542 @t_margin = margin
543 end
543 end
544 alias_method :set_top_margin, :SetTopMargin
544 alias_method :set_top_margin, :SetTopMargin
545
545
546 #
546 #
547 # Defines the right margin. The method can be called before creating the first page.
547 # Defines the right margin. The method can be called before creating the first page.
548 # @param float :margin The margin.
548 # @param float :margin The margin.
549 # @since 1.5
549 # @since 1.5
550 # @see SetLeftMargin(), SetTopMargin(), SetAutoPageBreak(), SetMargins()
550 # @see SetLeftMargin(), SetTopMargin(), SetAutoPageBreak(), SetMargins()
551 #
551 #
552 def SetRightMargin(margin)
552 def SetRightMargin(margin)
553 #Set right margin
553 #Set right margin
554 @r_margin = margin
554 @r_margin = margin
555 end
555 end
556 alias_method :set_right_margin, :SetRightMargin
556 alias_method :set_right_margin, :SetRightMargin
557
557
558 #
558 #
559 # Enables or disables the automatic page breaking mode. When enabling, the second parameter is the distance from the bottom of the page that defines the triggering limit. By default, the mode is on and the margin is 2 cm.
559 # Enables or disables the automatic page breaking mode. When enabling, the second parameter is the distance from the bottom of the page that defines the triggering limit. By default, the mode is on and the margin is 2 cm.
560 # @param boolean :auto Boolean indicating if mode should be on or off.
560 # @param boolean :auto Boolean indicating if mode should be on or off.
561 # @param float :margin Distance from the bottom of the page.
561 # @param float :margin Distance from the bottom of the page.
562 # @since 1.0
562 # @since 1.0
563 # @see Cell(), MultiCell(), AcceptPageBreak()
563 # @see Cell(), MultiCell(), AcceptPageBreak()
564 #
564 #
565 def SetAutoPageBreak(auto, margin=0)
565 def SetAutoPageBreak(auto, margin=0)
566 #Set auto page break mode and triggering margin
566 #Set auto page break mode and triggering margin
567 @auto_page_break = auto
567 @auto_page_break = auto
568 @b_margin = margin
568 @b_margin = margin
569 @page_break_trigger = @h - margin
569 @page_break_trigger = @h - margin
570 end
570 end
571 alias_method :set_auto_page_break, :SetAutoPageBreak
571 alias_method :set_auto_page_break, :SetAutoPageBreak
572
572
573 #
573 #
574 # Defines the way the document is to be displayed by the viewer. The zoom level can be set: pages can be displayed entirely on screen, occupy the full width of the window, use real size, be scaled by a specific zooming factor or use viewer default (configured in the Preferences menu of Acrobat). The page layout can be specified too: single at once, continuous display, two columns or viewer default. By default, documents use the full width mode with continuous display.
574 # Defines the way the document is to be displayed by the viewer. The zoom level can be set: pages can be displayed entirely on screen, occupy the full width of the window, use real size, be scaled by a specific zooming factor or use viewer default (configured in the Preferences menu of Acrobat). The page layout can be specified too: single at once, continuous display, two columns or viewer default. By default, documents use the full width mode with continuous display.
575 # @param mixed :zoom The zoom to use. It can be one of the following string values or a number indicating the zooming factor to use. <ul><li>fullpage: displays the entire page on screen </li><li>fullwidth: uses maximum width of window</li><li>real: uses real size (equivalent to 100% zoom)</li><li>default: uses viewer default mode</li></ul>
575 # @param mixed :zoom The zoom to use. It can be one of the following string values or a number indicating the zooming factor to use. <ul><li>fullpage: displays the entire page on screen </li><li>fullwidth: uses maximum width of window</li><li>real: uses real size (equivalent to 100% zoom)</li><li>default: uses viewer default mode</li></ul>
576 # @param string :layout The page layout. Possible values are:<ul><li>single: displays one page at once</li><li>continuous: displays pages continuously (default)</li><li>two: displays two pages on two columns</li><li>default: uses viewer default mode</li></ul>
576 # @param string :layout The page layout. Possible values are:<ul><li>single: displays one page at once</li><li>continuous: displays pages continuously (default)</li><li>two: displays two pages on two columns</li><li>default: uses viewer default mode</li></ul>
577 # @since 1.2
577 # @since 1.2
578 #
578 #
579 def SetDisplayMode(zoom, layout = 'continuous')
579 def SetDisplayMode(zoom, layout = 'continuous')
580 #Set display mode in viewer
580 #Set display mode in viewer
581 if (zoom == 'fullpage' or zoom == 'fullwidth' or zoom == 'real' or zoom == 'default' or !zoom.is_a?(String))
581 if (zoom == 'fullpage' or zoom == 'fullwidth' or zoom == 'real' or zoom == 'default' or !zoom.is_a?(String))
582 @zoom_mode = zoom
582 @zoom_mode = zoom
583 else
583 else
584 Error("Incorrect zoom display mode: #{zoom}")
584 Error("Incorrect zoom display mode: #{zoom}")
585 end
585 end
586 if (layout == 'single' or layout == 'continuous' or layout == 'two' or layout == 'default')
586 if (layout == 'single' or layout == 'continuous' or layout == 'two' or layout == 'default')
587 @layout_mode = layout
587 @layout_mode = layout
588 else
588 else
589 Error("Incorrect layout display mode: #{layout}")
589 Error("Incorrect layout display mode: #{layout}")
590 end
590 end
591 end
591 end
592 alias_method :set_display_mode, :SetDisplayMode
592 alias_method :set_display_mode, :SetDisplayMode
593
593
594 #
594 #
595 # Activates or deactivates page compression. When activated, the internal representation of each page is compressed, which leads to a compression ratio of about 2 for the resulting document. Compression is on by default.
595 # Activates or deactivates page compression. When activated, the internal representation of each page is compressed, which leads to a compression ratio of about 2 for the resulting document. Compression is on by default.
596 # Note: the Zlib extension is required for this feature. If not present, compression will be turned off.
596 # Note: the Zlib extension is required for this feature. If not present, compression will be turned off.
597 # @param boolean :compress Boolean indicating if compression must be enabled.
597 # @param boolean :compress Boolean indicating if compression must be enabled.
598 # @since 1.4
598 # @since 1.4
599 #
599 #
600 def SetCompression(compress)
600 def SetCompression(compress)
601 #Set page compression
601 #Set page compression
602 if (respond_to?('gzcompress'))
602 if (respond_to?('gzcompress'))
603 @compress = compress
603 @compress = compress
604 else
604 else
605 @compress = false
605 @compress = false
606 end
606 end
607 end
607 end
608 alias_method :set_compression, :SetCompression
608 alias_method :set_compression, :SetCompression
609
609
610 #
610 #
611 # Defines the title of the document.
611 # Defines the title of the document.
612 # @param string :title The title.
612 # @param string :title The title.
613 # @since 1.2
613 # @since 1.2
614 # @see SetAuthor(), SetCreator(), SetKeywords(), SetSubject()
614 # @see SetAuthor(), SetCreator(), SetKeywords(), SetSubject()
615 #
615 #
616 def SetTitle(title)
616 def SetTitle(title)
617 #Title of document
617 #Title of document
618 @title = title
618 @title = title
619 end
619 end
620 alias_method :set_title, :SetTitle
620 alias_method :set_title, :SetTitle
621
621
622 #
622 #
623 # Defines the subject of the document.
623 # Defines the subject of the document.
624 # @param string :subject The subject.
624 # @param string :subject The subject.
625 # @since 1.2
625 # @since 1.2
626 # @see SetAuthor(), SetCreator(), SetKeywords(), SetTitle()
626 # @see SetAuthor(), SetCreator(), SetKeywords(), SetTitle()
627 #
627 #
628 def SetSubject(subject)
628 def SetSubject(subject)
629 #Subject of document
629 #Subject of document
630 @subject = subject
630 @subject = subject
631 end
631 end
632 alias_method :set_subject, :SetSubject
632 alias_method :set_subject, :SetSubject
633
633
634 #
634 #
635 # Defines the author of the document.
635 # Defines the author of the document.
636 # @param string :author The name of the author.
636 # @param string :author The name of the author.
637 # @since 1.2
637 # @since 1.2
638 # @see SetCreator(), SetKeywords(), SetSubject(), SetTitle()
638 # @see SetCreator(), SetKeywords(), SetSubject(), SetTitle()
639 #
639 #
640 def SetAuthor(author)
640 def SetAuthor(author)
641 #Author of document
641 #Author of document
642 @author = author
642 @author = author
643 end
643 end
644 alias_method :set_author, :SetAuthor
644 alias_method :set_author, :SetAuthor
645
645
646 #
646 #
647 # Associates keywords with the document, generally in the form 'keyword1 keyword2 ...'.
647 # Associates keywords with the document, generally in the form 'keyword1 keyword2 ...'.
648 # @param string :keywords The list of keywords.
648 # @param string :keywords The list of keywords.
649 # @since 1.2
649 # @since 1.2
650 # @see SetAuthor(), SetCreator(), SetSubject(), SetTitle()
650 # @see SetAuthor(), SetCreator(), SetSubject(), SetTitle()
651 #
651 #
652 def SetKeywords(keywords)
652 def SetKeywords(keywords)
653 #Keywords of document
653 #Keywords of document
654 @keywords = keywords
654 @keywords = keywords
655 end
655 end
656 alias_method :set_keywords, :SetKeywords
656 alias_method :set_keywords, :SetKeywords
657
657
658 #
658 #
659 # Defines the creator of the document. This is typically the name of the application that generates the PDF.
659 # Defines the creator of the document. This is typically the name of the application that generates the PDF.
660 # @param string :creator The name of the creator.
660 # @param string :creator The name of the creator.
661 # @since 1.2
661 # @since 1.2
662 # @see SetAuthor(), SetKeywords(), SetSubject(), SetTitle()
662 # @see SetAuthor(), SetKeywords(), SetSubject(), SetTitle()
663 #
663 #
664 def SetCreator(creator)
664 def SetCreator(creator)
665 #Creator of document
665 #Creator of document
666 @creator = creator
666 @creator = creator
667 end
667 end
668 alias_method :set_creator, :SetCreator
668 alias_method :set_creator, :SetCreator
669
669
670 #
670 #
671 # Defines an alias for the total number of pages. It will be substituted as the document is closed.<br />
671 # Defines an alias for the total number of pages. It will be substituted as the document is closed.<br />
672 # <b>Example:</b><br />
672 # <b>Example:</b><br />
673 # <pre>
673 # <pre>
674 # class PDF extends TCPDF {
674 # class PDF extends TCPDF {
675 # def Footer()
675 # def Footer()
676 # #Go to 1.5 cm from bottom
676 # #Go to 1.5 cm from bottom
677 # SetY(-15);
677 # SetY(-15);
678 # #Select Arial italic 8
678 # #Select Arial italic 8
679 # SetFont('Arial','I',8);
679 # SetFont('Arial','I',8);
680 # #Print current and total page numbers
680 # #Print current and total page numbers
681 # Cell(0,10,'Page '.PageNo().'/{nb}',0,0,'C');
681 # Cell(0,10,'Page '.PageNo().'/{nb}',0,0,'C');
682 # end
682 # end
683 # }
683 # }
684 # :pdf=new PDF();
684 # :pdf=new PDF();
685 # :pdf->alias_nb_pages();
685 # :pdf->alias_nb_pages();
686 # </pre>
686 # </pre>
687 # @param string :alias The alias. Default valuenb}.
687 # @param string :alias The alias. Default valuenb}.
688 # @since 1.4
688 # @since 1.4
689 # @see PageNo(), Footer()
689 # @see PageNo(), Footer()
690 #
690 #
691 def AliasNbPages(alias_nb ='{nb}')
691 def AliasNbPages(alias_nb ='{nb}')
692 #Define an alias for total number of pages
692 #Define an alias for total number of pages
693 @alias_nb_pages = escapetext(alias_nb)
693 @alias_nb_pages = escapetext(alias_nb)
694 end
694 end
695 alias_method :alias_nb_pages, :AliasNbPages
695 alias_method :alias_nb_pages, :AliasNbPages
696
696
697 #
697 #
698 # This method is automatically called in case of fatal error; it simply outputs the message and halts the execution. An inherited class may override it to customize the error handling but should always halt the script, or the resulting document would probably be invalid.
698 # This method is automatically called in case of fatal error; it simply outputs the message and halts the execution. An inherited class may override it to customize the error handling but should always halt the script, or the resulting document would probably be invalid.
699 # 2004-06-11 :: Nicola Asuni : changed bold tag with strong
699 # 2004-06-11 :: Nicola Asuni : changed bold tag with strong
700 # @param string :msg The error message
700 # @param string :msg The error message
701 # @since 1.0
701 # @since 1.0
702 #
702 #
703 def Error(msg)
703 def Error(msg)
704 #Fatal error
704 #Fatal error
705 raise ("TCPDF error: #{msg}")
705 raise ("TCPDF error: #{msg}")
706 end
706 end
707 alias_method :error, :Error
707 alias_method :error, :Error
708
708
709 #
709 #
710 # This method begins the generation of the PDF document. It is not necessary to call it explicitly because AddPage() does it automatically.
710 # This method begins the generation of the PDF document. It is not necessary to call it explicitly because AddPage() does it automatically.
711 # Note: no page is created by this method
711 # Note: no page is created by this method
712 # @since 1.0
712 # @since 1.0
713 # @see AddPage(), Close()
713 # @see AddPage(), Close()
714 #
714 #
715 def Open()
715 def Open()
716 #Begin document
716 #Begin document
717 @state = 1
717 @state = 1
718 end
718 end
719 # alias_method :open, :Open
719 # alias_method :open, :Open
720
720
721 #
721 #
722 # Terminates the PDF document. It is not necessary to call this method explicitly because Output() does it automatically. If the document contains no page, AddPage() is called to prevent from getting an invalid document.
722 # Terminates the PDF document. It is not necessary to call this method explicitly because Output() does it automatically. If the document contains no page, AddPage() is called to prevent from getting an invalid document.
723 # @since 1.0
723 # @since 1.0
724 # @see Open(), Output()
724 # @see Open(), Output()
725 #
725 #
726 def Close()
726 def Close()
727 #Terminate document
727 #Terminate document
728 if (@state==3)
728 if (@state==3)
729 return;
729 return;
730 end
730 end
731 if (@page==0)
731 if (@page==0)
732 AddPage();
732 AddPage();
733 end
733 end
734 #Page footer
734 #Page footer
735 @in_footer=true;
735 @in_footer=true;
736 Footer();
736 Footer();
737 @in_footer=false;
737 @in_footer=false;
738 #Close page
738 #Close page
739 endpage();
739 endpage();
740 #Close document
740 #Close document
741 enddoc();
741 enddoc();
742 end
742 end
743 # alias_method :close, :Close
743 # alias_method :close, :Close
744
744
745 #
745 #
746 # Adds a new page to the document. If a page is already present, the Footer() method is called first to output the footer. Then the page is added, the current position set to the top-left corner according to the left and top margins, and Header() is called to display the header.
746 # Adds a new page to the document. If a page is already present, the Footer() method is called first to output the footer. Then the page is added, the current position set to the top-left corner according to the left and top margins, and Header() is called to display the header.
747 # The font which was set before calling is automatically restored. There is no need to call SetFont() again if you want to continue with the same font. The same is true for colors and line width.
747 # The font which was set before calling is automatically restored. There is no need to call SetFont() again if you want to continue with the same font. The same is true for colors and line width.
748 # The origin of the coordinate system is at the top-left corner and increasing ordinates go downwards.
748 # The origin of the coordinate system is at the top-left corner and increasing ordinates go downwards.
749 # @param string :orientation Page orientation. Possible values are (case insensitive):<ul><li>P or Portrait</li><li>L or Landscape</li></ul> The default value is the one passed to the constructor.
749 # @param string :orientation Page orientation. Possible values are (case insensitive):<ul><li>P or Portrait</li><li>L or Landscape</li></ul> The default value is the one passed to the constructor.
750 # @since 1.0
750 # @since 1.0
751 # @see TCPDF(), Header(), Footer(), SetMargins()
751 # @see TCPDF(), Header(), Footer(), SetMargins()
752 #
752 #
753 def AddPage(orientation='')
753 def AddPage(orientation='')
754 #Start a new page
754 #Start a new page
755 if (@state==0)
755 if (@state==0)
756 Open();
756 Open();
757 end
757 end
758 family=@font_family;
758 family=@font_family;
759 style=@font_style + (@underline ? 'U' : '') + (@deleted ? 'D' : '');
759 style=@font_style + (@underline ? 'U' : '') + (@deleted ? 'D' : '');
760 size=@font_size_pt;
760 size=@font_size_pt;
761 lw=@line_width;
761 lw=@line_width;
762 dc=@draw_color;
762 dc=@draw_color;
763 fc=@fill_color;
763 fc=@fill_color;
764 tc=@text_color;
764 tc=@text_color;
765 cf=@color_flag;
765 cf=@color_flag;
766 if (@page>0)
766 if (@page>0)
767 #Page footer
767 #Page footer
768 @in_footer=true;
768 @in_footer=true;
769 Footer();
769 Footer();
770 @in_footer=false;
770 @in_footer=false;
771 #Close page
771 #Close page
772 endpage();
772 endpage();
773 end
773 end
774 #Start new page
774 #Start new page
775 beginpage(orientation);
775 beginpage(orientation);
776 #Set line cap style to square
776 #Set line cap style to square
777 out('2 J');
777 out('2 J');
778 #Set line width
778 #Set line width
779 @line_width = lw;
779 @line_width = lw;
780 out(sprintf('%.2f w', lw*@k));
780 out(sprintf('%.2f w', lw*@k));
781 #Set font
781 #Set font
782 if (family)
782 if (family)
783 SetFont(family, style, size);
783 SetFont(family, style, size);
784 end
784 end
785 #Set colors
785 #Set colors
786 @draw_color = dc;
786 @draw_color = dc;
787 if (dc!='0 G')
787 if (dc!='0 G')
788 out(dc);
788 out(dc);
789 end
789 end
790 @fill_color = fc;
790 @fill_color = fc;
791 if (fc!='0 g')
791 if (fc!='0 g')
792 out(fc);
792 out(fc);
793 end
793 end
794 @text_color = tc;
794 @text_color = tc;
795 @color_flag = cf;
795 @color_flag = cf;
796 #Page header
796 #Page header
797 Header();
797 Header();
798 #Restore line width
798 #Restore line width
799 if (@line_width != lw)
799 if (@line_width != lw)
800 @line_width = lw;
800 @line_width = lw;
801 out(sprintf('%.2f w', lw*@k));
801 out(sprintf('%.2f w', lw*@k));
802 end
802 end
803 #Restore font
803 #Restore font
804 if (family)
804 if (family)
805 SetFont(family, style, size);
805 SetFont(family, style, size);
806 end
806 end
807 #Restore colors
807 #Restore colors
808 if (@draw_color != dc)
808 if (@draw_color != dc)
809 @draw_color = dc;
809 @draw_color = dc;
810 out(dc);
810 out(dc);
811 end
811 end
812 if (@fill_color != fc)
812 if (@fill_color != fc)
813 @fill_color = fc;
813 @fill_color = fc;
814 out(fc);
814 out(fc);
815 end
815 end
816 @text_color = tc;
816 @text_color = tc;
817 @color_flag = cf;
817 @color_flag = cf;
818 end
818 end
819 alias_method :add_page, :AddPage
819 alias_method :add_page, :AddPage
820
820
821 #
821 #
822 # Rotate object.
822 # Rotate object.
823 # @param float :angle angle in degrees for counter-clockwise rotation
823 # @param float :angle angle in degrees for counter-clockwise rotation
824 # @param int :x abscissa of the rotation center. Default is current x position
824 # @param int :x abscissa of the rotation center. Default is current x position
825 # @param int :y ordinate of the rotation center. Default is current y position
825 # @param int :y ordinate of the rotation center. Default is current y position
826 #
826 #
827 def Rotate(angle, x="", y="")
827 def Rotate(angle, x="", y="")
828
828
829 if (x == '')
829 if (x == '')
830 x = @x;
830 x = @x;
831 end
831 end
832
832
833 if (y == '')
833 if (y == '')
834 y = @y;
834 y = @y;
835 end
835 end
836
836
837 if (@rtl)
837 if (@rtl)
838 x = @w - x;
838 x = @w - x;
839 angle = -@angle;
839 angle = -@angle;
840 end
840 end
841
841
842 y = (@h - y) * @k;
842 y = (@h - y) * @k;
843 x *= @k;
843 x *= @k;
844
844
845 # calculate elements of transformation matrix
845 # calculate elements of transformation matrix
846 tm = []
846 tm = []
847 tm[0] = ::Math::cos(deg2rad(angle));
847 tm[0] = ::Math::cos(deg2rad(angle));
848 tm[1] = ::Math::sin(deg2rad(angle));
848 tm[1] = ::Math::sin(deg2rad(angle));
849 tm[2] = -tm[1];
849 tm[2] = -tm[1];
850 tm[3] = tm[0];
850 tm[3] = tm[0];
851 tm[4] = x + tm[1] * y - tm[0] * x;
851 tm[4] = x + tm[1] * y - tm[0] * x;
852 tm[5] = y - tm[0] * y - tm[1] * x;
852 tm[5] = y - tm[0] * y - tm[1] * x;
853
853
854 # generate the transformation matrix
854 # generate the transformation matrix
855 Transform(tm);
855 Transform(tm);
856 end
856 end
857 alias_method :rotate, :Rotate
857 alias_method :rotate, :Rotate
858
858
859 #
859 #
860 # Starts a 2D tranformation saving current graphic state.
860 # Starts a 2D tranformation saving current graphic state.
861 # This function must be called before scaling, mirroring, translation, rotation and skewing.
861 # This function must be called before scaling, mirroring, translation, rotation and skewing.
862 # Use StartTransform() before, and StopTransform() after the transformations to restore the normal behavior.
862 # Use StartTransform() before, and StopTransform() after the transformations to restore the normal behavior.
863 #
863 #
864 def StartTransform
864 def StartTransform
865 out('q');
865 out('q');
866 end
866 end
867 alias_method :start_transform, :StartTransform
867 alias_method :start_transform, :StartTransform
868
868
869 #
869 #
870 # Stops a 2D tranformation restoring previous graphic state.
870 # Stops a 2D tranformation restoring previous graphic state.
871 # This function must be called after scaling, mirroring, translation, rotation and skewing.
871 # This function must be called after scaling, mirroring, translation, rotation and skewing.
872 # Use StartTransform() before, and StopTransform() after the transformations to restore the normal behavior.
872 # Use StartTransform() before, and StopTransform() after the transformations to restore the normal behavior.
873 #
873 #
874 def StopTransform
874 def StopTransform
875 out('Q');
875 out('Q');
876 end
876 end
877 alias_method :stop_transform, :StopTransform
877 alias_method :stop_transform, :StopTransform
878
878
879 #
879 #
880 # Apply graphic transformations.
880 # Apply graphic transformations.
881 # @since 2.1.000 (2008-01-07)
881 # @since 2.1.000 (2008-01-07)
882 # @see StartTransform(), StopTransform()
882 # @see StartTransform(), StopTransform()
883 #
883 #
884 def Transform(tm)
884 def Transform(tm)
885 x = out(sprintf('%.3f %.3f %.3f %.3f %.3f %.3f cm', tm[0], tm[1], tm[2], tm[3], tm[4], tm[5]));
885 x = out(sprintf('%.3f %.3f %.3f %.3f %.3f %.3f cm', tm[0], tm[1], tm[2], tm[3], tm[4], tm[5]));
886 end
886 end
887 alias_method :transform, :Transform
887 alias_method :transform, :Transform
888
888
889 #
889 #
890 # Set header data.
890 # Set header data.
891 # @param string :ln header image logo
891 # @param string :ln header image logo
892 # @param string :lw header image logo width in mm
892 # @param string :lw header image logo width in mm
893 # @param string :ht string to print as title on document header
893 # @param string :ht string to print as title on document header
894 # @param string :hs string to print on document header
894 # @param string :hs string to print on document header
895 #
895 #
896 def SetHeaderData(ln="", lw=0, ht="", hs="")
896 def SetHeaderData(ln="", lw=0, ht="", hs="")
897 @header_logo = ln || ""
897 @header_logo = ln || ""
898 @header_logo_width = lw || 0
898 @header_logo_width = lw || 0
899 @header_title = ht || ""
899 @header_title = ht || ""
900 @header_string = hs || ""
900 @header_string = hs || ""
901 end
901 end
902 alias_method :set_header_data, :SetHeaderData
902 alias_method :set_header_data, :SetHeaderData
903
903
904 #
904 #
905 # Set header margin.
905 # Set header margin.
906 # (minimum distance between header and top page margin)
906 # (minimum distance between header and top page margin)
907 # @param int :hm distance in millimeters
907 # @param int :hm distance in millimeters
908 #
908 #
909 def SetHeaderMargin(hm=10)
909 def SetHeaderMargin(hm=10)
910 @header_margin = hm;
910 @header_margin = hm;
911 end
911 end
912 alias_method :set_header_margin, :SetHeaderMargin
912 alias_method :set_header_margin, :SetHeaderMargin
913
913
914 #
914 #
915 # Set footer margin.
915 # Set footer margin.
916 # (minimum distance between footer and bottom page margin)
916 # (minimum distance between footer and bottom page margin)
917 # @param int :fm distance in millimeters
917 # @param int :fm distance in millimeters
918 #
918 #
919 def SetFooterMargin(fm=10)
919 def SetFooterMargin(fm=10)
920 @footer_margin = fm;
920 @footer_margin = fm;
921 end
921 end
922 alias_method :set_footer_margin, :SetFooterMargin
922 alias_method :set_footer_margin, :SetFooterMargin
923
923
924 #
924 #
925 # Set a flag to print page header.
925 # Set a flag to print page header.
926 # @param boolean :val set to true to print the page header (default), false otherwise.
926 # @param boolean :val set to true to print the page header (default), false otherwise.
927 #
927 #
928 def SetPrintHeader(val=true)
928 def SetPrintHeader(val=true)
929 @print_header = val;
929 @print_header = val;
930 end
930 end
931 alias_method :set_print_header, :SetPrintHeader
931 alias_method :set_print_header, :SetPrintHeader
932
932
933 #
933 #
934 # Set a flag to print page footer.
934 # Set a flag to print page footer.
935 # @param boolean :value set to true to print the page footer (default), false otherwise.
935 # @param boolean :value set to true to print the page footer (default), false otherwise.
936 #
936 #
937 def SetPrintFooter(val=true)
937 def SetPrintFooter(val=true)
938 @print_footer = val;
938 @print_footer = val;
939 end
939 end
940 alias_method :set_print_footer, :SetPrintFooter
940 alias_method :set_print_footer, :SetPrintFooter
941
941
942 #
942 #
943 # This method is used to render the page header.
943 # This method is used to render the page header.
944 # It is automatically called by AddPage() and could be overwritten in your own inherited class.
944 # It is automatically called by AddPage() and could be overwritten in your own inherited class.
945 #
945 #
946 def Header()
946 def Header()
947 if (@print_header)
947 if (@print_header)
948 if (@original_l_margin.nil?)
948 if (@original_l_margin.nil?)
949 @original_l_margin = @l_margin;
949 @original_l_margin = @l_margin;
950 end
950 end
951 if (@original_r_margin.nil?)
951 if (@original_r_margin.nil?)
952 @original_r_margin = @r_margin;
952 @original_r_margin = @r_margin;
953 end
953 end
954
954
955 #set current position
955 #set current position
956 SetXY(@original_l_margin, @header_margin);
956 SetXY(@original_l_margin, @header_margin);
957
957
958 if ((@header_logo) and (@header_logo != @@k_blank_image))
958 if ((@header_logo) and (@header_logo != @@k_blank_image))
959 Image(@header_logo, @original_l_margin, @header_margin, @header_logo_width);
959 Image(@header_logo, @original_l_margin, @header_margin, @header_logo_width);
960 else
960 else
961 @img_rb_y = GetY();
961 @img_rb_y = GetY();
962 end
962 end
963
963
964 cell_height = ((@@k_cell_height_ratio * @header_font[2]) / @k).round(2)
964 cell_height = ((@@k_cell_height_ratio * @header_font[2]) / @k).round(2)
965
965
966 header_x = @original_l_margin + (@header_logo_width * 1.05); #set left margin for text data cell
966 header_x = @original_l_margin + (@header_logo_width * 1.05); #set left margin for text data cell
967
967
968 # header title
968 # header title
969 SetFont(@header_font[0], 'B', @header_font[2] + 1);
969 SetFont(@header_font[0], 'B', @header_font[2] + 1);
970 SetX(header_x);
970 SetX(header_x);
971 Cell(@header_width, cell_height, @header_title, 0, 1, 'L');
971 Cell(@header_width, cell_height, @header_title, 0, 1, 'L');
972
972
973 # header string
973 # header string
974 SetFont(@header_font[0], @header_font[1], @header_font[2]);
974 SetFont(@header_font[0], @header_font[1], @header_font[2]);
975 SetX(header_x);
975 SetX(header_x);
976 MultiCell(@header_width, cell_height, @header_string, 0, 'L', 0);
976 MultiCell(@header_width, cell_height, @header_string, 0, 'L', 0);
977
977
978 # print an ending header line
978 # print an ending header line
979 if (@header_width)
979 if (@header_width)
980 #set style for cell border
980 #set style for cell border
981 SetLineWidth(0.3);
981 SetLineWidth(0.3);
982 SetDrawColor(0, 0, 0);
982 SetDrawColor(0, 0, 0);
983 SetY(1 + (@img_rb_y > GetY() ? @img_rb_y : GetY()));
983 SetY(1 + (@img_rb_y > GetY() ? @img_rb_y : GetY()));
984 SetX(@original_l_margin);
984 SetX(@original_l_margin);
985 Cell(0, 0, '', 'T', 0, 'C');
985 Cell(0, 0, '', 'T', 0, 'C');
986 end
986 end
987
987
988 #restore position
988 #restore position
989 SetXY(@original_l_margin, @t_margin);
989 SetXY(@original_l_margin, @t_margin);
990 end
990 end
991 end
991 end
992 alias_method :header, :Header
992 alias_method :header, :Header
993
993
994 #
994 #
995 # This method is used to render the page footer.
995 # This method is used to render the page footer.
996 # It is automatically called by AddPage() and could be overwritten in your own inherited class.
996 # It is automatically called by AddPage() and could be overwritten in your own inherited class.
997 #
997 #
998 def Footer()
998 def Footer()
999 if (@print_footer)
999 if (@print_footer)
1000
1000
1001 if (@original_l_margin.nil?)
1001 if (@original_l_margin.nil?)
1002 @original_l_margin = @l_margin;
1002 @original_l_margin = @l_margin;
1003 end
1003 end
1004 if (@original_r_margin.nil?)
1004 if (@original_r_margin.nil?)
1005 @original_r_margin = @r_margin;
1005 @original_r_margin = @r_margin;
1006 end
1006 end
1007
1007
1008 #set font
1008 #set font
1009 SetFont(@footer_font[0], @footer_font[1] , @footer_font[2]);
1009 SetFont(@footer_font[0], @footer_font[1] , @footer_font[2]);
1010 #set style for cell border
1010 #set style for cell border
1011 line_width = 0.3;
1011 line_width = 0.3;
1012 SetLineWidth(line_width);
1012 SetLineWidth(line_width);
1013 SetDrawColor(0, 0, 0);
1013 SetDrawColor(0, 0, 0);
1014
1014
1015 footer_height = ((@@k_cell_height_ratio * @footer_font[2]) / @k).round; #footer height, was , 2)
1015 footer_height = ((@@k_cell_height_ratio * @footer_font[2]) / @k).round; #footer height, was , 2)
1016 #get footer y position
1016 #get footer y position
1017 footer_y = @h - @footer_margin - footer_height;
1017 footer_y = @h - @footer_margin - footer_height;
1018 #set current position
1018 #set current position
1019 SetXY(@original_l_margin, footer_y);
1019 SetXY(@original_l_margin, footer_y);
1020
1020
1021 #print document barcode
1021 #print document barcode
1022 if (@barcode)
1022 if (@barcode)
1023 Ln();
1023 Ln();
1024 barcode_width = ((@w - @original_l_margin - @original_r_margin)).round; #max width
1024 barcode_width = ((@w - @original_l_margin - @original_r_margin)).round; #max width
1025 writeBarcode(@original_l_margin, footer_y + line_width, barcode_width, footer_height - line_width, "C128B", false, false, 2, @barcode);
1025 writeBarcode(@original_l_margin, footer_y + line_width, barcode_width, footer_height - line_width, "C128B", false, false, 2, @barcode);
1026 end
1026 end
1027
1027
1028 SetXY(@original_l_margin, footer_y);
1028 SetXY(@original_l_margin, footer_y);
1029
1029
1030 #Print page number
1030 #Print page number
1031 Cell(0, footer_height, @l['w_page'] + " " + PageNo().to_s + ' / {nb}', 'T', 0, 'R');
1031 Cell(0, footer_height, @l['w_page'] + " " + PageNo().to_s + ' / {nb}', 'T', 0, 'R');
1032 end
1032 end
1033 end
1033 end
1034 alias_method :footer, :Footer
1034 alias_method :footer, :Footer
1035
1035
1036 #
1036 #
1037 # Returns the current page number.
1037 # Returns the current page number.
1038 # @return int page number
1038 # @return int page number
1039 # @since 1.0
1039 # @since 1.0
1040 # @see alias_nb_pages()
1040 # @see alias_nb_pages()
1041 #
1041 #
1042 def PageNo()
1042 def PageNo()
1043 #Get current page number
1043 #Get current page number
1044 return @page;
1044 return @page;
1045 end
1045 end
1046 alias_method :page_no, :PageNo
1046 alias_method :page_no, :PageNo
1047
1047
1048 #
1048 #
1049 # Defines the color used for all drawing operations (lines, rectangles and cell borders). It can be expressed in RGB components or gray scale. The method can be called before the first page is created and the value is retained from page to page.
1049 # Defines the color used for all drawing operations (lines, rectangles and cell borders). It can be expressed in RGB components or gray scale. The method can be called before the first page is created and the value is retained from page to page.
1050 # @param int :r If g et b are given, red component; if not, indicates the gray level. Value between 0 and 255
1050 # @param int :r If g et b are given, red component; if not, indicates the gray level. Value between 0 and 255
1051 # @param int :g Green component (between 0 and 255)
1051 # @param int :g Green component (between 0 and 255)
1052 # @param int :b Blue component (between 0 and 255)
1052 # @param int :b Blue component (between 0 and 255)
1053 # @since 1.3
1053 # @since 1.3
1054 # @see SetFillColor(), SetTextColor(), Line(), Rect(), Cell(), MultiCell()
1054 # @see SetFillColor(), SetTextColor(), Line(), Rect(), Cell(), MultiCell()
1055 #
1055 #
1056 def SetDrawColor(r, g=-1, b=-1)
1056 def SetDrawColor(r, g=-1, b=-1)
1057 #Set color for all stroking operations
1057 #Set color for all stroking operations
1058 if ((r==0 and g==0 and b==0) or g==-1)
1058 if ((r==0 and g==0 and b==0) or g==-1)
1059 @draw_color=sprintf('%.3f G', r/255.0);
1059 @draw_color=sprintf('%.3f G', r/255.0);
1060 else
1060 else
1061 @draw_color=sprintf('%.3f %.3f %.3f RG', r/255.0, g/255.0, b/255.0);
1061 @draw_color=sprintf('%.3f %.3f %.3f RG', r/255.0, g/255.0, b/255.0);
1062 end
1062 end
1063 if (@page>0)
1063 if (@page>0)
1064 out(@draw_color);
1064 out(@draw_color);
1065 end
1065 end
1066 end
1066 end
1067 alias_method :set_draw_color, :SetDrawColor
1067 alias_method :set_draw_color, :SetDrawColor
1068
1068
1069 #
1069 #
1070 # Defines the color used for all filling operations (filled rectangles and cell backgrounds). It can be expressed in RGB components or gray scale. The method can be called before the first page is created and the value is retained from page to page.
1070 # Defines the color used for all filling operations (filled rectangles and cell backgrounds). It can be expressed in RGB components or gray scale. The method can be called before the first page is created and the value is retained from page to page.
1071 # @param int :r If g et b are given, red component; if not, indicates the gray level. Value between 0 and 255
1071 # @param int :r If g et b are given, red component; if not, indicates the gray level. Value between 0 and 255
1072 # @param int :g Green component (between 0 and 255)
1072 # @param int :g Green component (between 0 and 255)
1073 # @param int :b Blue component (between 0 and 255)
1073 # @param int :b Blue component (between 0 and 255)
1074 # @param boolean :storeprev if true stores the RGB array on :prevfill_color variable.
1074 # @param boolean :storeprev if true stores the RGB array on :prevfill_color variable.
1075 # @since 1.3
1075 # @since 1.3
1076 # @see SetDrawColor(), SetTextColor(), Rect(), Cell(), MultiCell()
1076 # @see SetDrawColor(), SetTextColor(), Rect(), Cell(), MultiCell()
1077 #
1077 #
1078 def SetFillColor(r, g=-1, b=-1, storeprev=false)
1078 def SetFillColor(r, g=-1, b=-1, storeprev=false)
1079 #Set color for all filling operations
1079 #Set color for all filling operations
1080 if ((r==0 and g==0 and b==0) or g==-1)
1080 if ((r==0 and g==0 and b==0) or g==-1)
1081 @fill_color=sprintf('%.3f g', r/255.0);
1081 @fill_color=sprintf('%.3f g', r/255.0);
1082 else
1082 else
1083 @fill_color=sprintf('%.3f %.3f %.3f rg', r/255.0, g/255.0, b/255.0);
1083 @fill_color=sprintf('%.3f %.3f %.3f rg', r/255.0, g/255.0, b/255.0);
1084 end
1084 end
1085 @color_flag=(@fill_color!=@text_color);
1085 @color_flag=(@fill_color!=@text_color);
1086 if (@page>0)
1086 if (@page>0)
1087 out(@fill_color);
1087 out(@fill_color);
1088 end
1088 end
1089 if (storeprev)
1089 if (storeprev)
1090 # store color as previous value
1090 # store color as previous value
1091 @prevfill_color = [r, g, b]
1091 @prevfill_color = [r, g, b]
1092 end
1092 end
1093 end
1093 end
1094 alias_method :set_fill_color, :SetFillColor
1094 alias_method :set_fill_color, :SetFillColor
1095
1095
1096 # This hasn't been ported from tcpdf, it's a variation on SetTextColor for setting cmyk colors
1096 # This hasn't been ported from tcpdf, it's a variation on SetTextColor for setting cmyk colors
1097 def SetCmykFillColor(c, m, y, k, storeprev=false)
1097 def SetCmykFillColor(c, m, y, k, storeprev=false)
1098 #Set color for all filling operations
1098 #Set color for all filling operations
1099 @fill_color=sprintf('%.3f %.3f %.3f %.3f k', c, m, y, k);
1099 @fill_color=sprintf('%.3f %.3f %.3f %.3f k', c, m, y, k);
1100 @color_flag=(@fill_color!=@text_color);
1100 @color_flag=(@fill_color!=@text_color);
1101 if (storeprev)
1101 if (storeprev)
1102 # store color as previous value
1102 # store color as previous value
1103 @prevtext_color = [c, m, y, k]
1103 @prevtext_color = [c, m, y, k]
1104 end
1104 end
1105 if (@page>0)
1105 if (@page>0)
1106 out(@fill_color);
1106 out(@fill_color);
1107 end
1107 end
1108 end
1108 end
1109 alias_method :set_cmyk_fill_color, :SetCmykFillColor
1109 alias_method :set_cmyk_fill_color, :SetCmykFillColor
1110
1110
1111 #
1111 #
1112 # Defines the color used for text. It can be expressed in RGB components or gray scale. The method can be called before the first page is created and the value is retained from page to page.
1112 # Defines the color used for text. It can be expressed in RGB components or gray scale. The method can be called before the first page is created and the value is retained from page to page.
1113 # @param int :r If g et b are given, red component; if not, indicates the gray level. Value between 0 and 255
1113 # @param int :r If g et b are given, red component; if not, indicates the gray level. Value between 0 and 255
1114 # @param int :g Green component (between 0 and 255)
1114 # @param int :g Green component (between 0 and 255)
1115 # @param int :b Blue component (between 0 and 255)
1115 # @param int :b Blue component (between 0 and 255)
1116 # @param boolean :storeprev if true stores the RGB array on :prevtext_color variable.
1116 # @param boolean :storeprev if true stores the RGB array on :prevtext_color variable.
1117 # @since 1.3
1117 # @since 1.3
1118 # @see SetDrawColor(), SetFillColor(), Text(), Cell(), MultiCell()
1118 # @see SetDrawColor(), SetFillColor(), Text(), Cell(), MultiCell()
1119 #
1119 #
1120 def SetTextColor(r, g=-1, b=-1, storeprev=false)
1120 def SetTextColor(r, g=-1, b=-1, storeprev=false)
1121 #Set color for text
1121 #Set color for text
1122 if ((r==0 and :g==0 and :b==0) or :g==-1)
1122 if ((r==0 and :g==0 and :b==0) or :g==-1)
1123 @text_color=sprintf('%.3f g', r/255.0);
1123 @text_color=sprintf('%.3f g', r/255.0);
1124 else
1124 else
1125 @text_color=sprintf('%.3f %.3f %.3f rg', r/255.0, g/255.0, b/255.0);
1125 @text_color=sprintf('%.3f %.3f %.3f rg', r/255.0, g/255.0, b/255.0);
1126 end
1126 end
1127 @color_flag=(@fill_color!=@text_color);
1127 @color_flag=(@fill_color!=@text_color);
1128 if (storeprev)
1128 if (storeprev)
1129 # store color as previous value
1129 # store color as previous value
1130 @prevtext_color = [r, g, b]
1130 @prevtext_color = [r, g, b]
1131 end
1131 end
1132 end
1132 end
1133 alias_method :set_text_color, :SetTextColor
1133 alias_method :set_text_color, :SetTextColor
1134
1134
1135 # This hasn't been ported from tcpdf, it's a variation on SetTextColor for setting cmyk colors
1135 # This hasn't been ported from tcpdf, it's a variation on SetTextColor for setting cmyk colors
1136 def SetCmykTextColor(c, m, y, k, storeprev=false)
1136 def SetCmykTextColor(c, m, y, k, storeprev=false)
1137 #Set color for text
1137 #Set color for text
1138 @text_color=sprintf('%.3f %.3f %.3f %.3f k', c, m, y, k);
1138 @text_color=sprintf('%.3f %.3f %.3f %.3f k', c, m, y, k);
1139 @color_flag=(@fill_color!=@text_color);
1139 @color_flag=(@fill_color!=@text_color);
1140 if (storeprev)
1140 if (storeprev)
1141 # store color as previous value
1141 # store color as previous value
1142 @prevtext_color = [c, m, y, k]
1142 @prevtext_color = [c, m, y, k]
1143 end
1143 end
1144 end
1144 end
1145 alias_method :set_cmyk_text_color, :SetCmykTextColor
1145 alias_method :set_cmyk_text_color, :SetCmykTextColor
1146
1146
1147 #
1147 #
1148 # Returns the length of a string in user unit. A font must be selected.<br>
1148 # Returns the length of a string in user unit. A font must be selected.<br>
1149 # Support UTF-8 Unicode [Nicola Asuni, 2005-01-02]
1149 # Support UTF-8 Unicode [Nicola Asuni, 2005-01-02]
1150 # @param string :s The string whose length is to be computed
1150 # @param string :s The string whose length is to be computed
1151 # @return int
1151 # @return int
1152 # @since 1.2
1152 # @since 1.2
1153 #
1153 #
1154 def GetStringWidth(s)
1154 def GetStringWidth(s)
1155 #Get width of a string in the current font
1155 #Get width of a string in the current font
1156 s = s.to_s;
1156 s = s.to_s;
1157 cw = @current_font['cw']
1157 cw = @current_font['cw']
1158 w = 0;
1158 w = 0;
1159 if (@is_unicode)
1159 if (@is_unicode)
1160 unicode = UTF8StringToArray(s);
1160 unicode = UTF8StringToArray(s);
1161 unicode.each do |char|
1161 unicode.each do |char|
1162 if (!cw[char].nil?)
1162 if (!cw[char].nil?)
1163 w += cw[char];
1163 w += cw[char];
1164 # This should not happen. UTF8StringToArray should guarentee the array is ascii values.
1164 # This should not happen. UTF8StringToArray should guarentee the array is ascii values.
1165 # elsif (c!cw[char[0]].nil?)
1165 # elsif (c!cw[char[0]].nil?)
1166 # w += cw[char[0]];
1166 # w += cw[char[0]];
1167 # elsif (!cw[char.chr].nil?)
1167 # elsif (!cw[char.chr].nil?)
1168 # w += cw[char.chr];
1168 # w += cw[char.chr];
1169 elsif (!@current_font['desc']['MissingWidth'].nil?)
1169 elsif (!@current_font['desc']['MissingWidth'].nil?)
1170 w += @current_font['desc']['MissingWidth']; # set default size
1170 w += @current_font['desc']['MissingWidth']; # set default size
1171 else
1171 else
1172 w += 500;
1172 w += 500;
1173 end
1173 end
1174 end
1174 end
1175 else
1175 else
1176 s.each_byte do |c|
1176 s.each_byte do |c|
1177 if cw[c.chr]
1177 if cw[c.chr]
1178 w += cw[c.chr];
1178 w += cw[c.chr];
1179 elsif cw[?c.chr]
1179 elsif cw[?c.chr]
1180 w += cw[?c.chr]
1180 w += cw[?c.chr]
1181 end
1181 end
1182 end
1182 end
1183 end
1183 end
1184 return (w * @font_size / 1000.0);
1184 return (w * @font_size / 1000.0);
1185 end
1185 end
1186 alias_method :get_string_width, :GetStringWidth
1186 alias_method :get_string_width, :GetStringWidth
1187
1187
1188 #
1188 #
1189 # Defines the line width. By default, the value equals 0.2 mm. The method can be called before the first page is created and the value is retained from page to page.
1189 # Defines the line width. By default, the value equals 0.2 mm. The method can be called before the first page is created and the value is retained from page to page.
1190 # @param float :width The width.
1190 # @param float :width The width.
1191 # @since 1.0
1191 # @since 1.0
1192 # @see Line(), Rect(), Cell(), MultiCell()
1192 # @see Line(), Rect(), Cell(), MultiCell()
1193 #
1193 #
1194 def SetLineWidth(width)
1194 def SetLineWidth(width)
1195 #Set line width
1195 #Set line width
1196 @line_width = width;
1196 @line_width = width;
1197 if (@page>0)
1197 if (@page>0)
1198 out(sprintf('%.2f w', width*@k));
1198 out(sprintf('%.2f w', width*@k));
1199 end
1199 end
1200 end
1200 end
1201 alias_method :set_line_width, :SetLineWidth
1201 alias_method :set_line_width, :SetLineWidth
1202
1202
1203 #
1203 #
1204 # Draws a line between two points.
1204 # Draws a line between two points.
1205 # @param float :x1 Abscissa of first point
1205 # @param float :x1 Abscissa of first point
1206 # @param float :y1 Ordinate of first point
1206 # @param float :y1 Ordinate of first point
1207 # @param float :x2 Abscissa of second point
1207 # @param float :x2 Abscissa of second point
1208 # @param float :y2 Ordinate of second point
1208 # @param float :y2 Ordinate of second point
1209 # @since 1.0
1209 # @since 1.0
1210 # @see SetLineWidth(), SetDrawColor()
1210 # @see SetLineWidth(), SetDrawColor()
1211 #
1211 #
1212 def Line(x1, y1, x2, y2)
1212 def Line(x1, y1, x2, y2)
1213 #Draw a line
1213 #Draw a line
1214 out(sprintf('%.2f %.2f m %.2f %.2f l S', x1 * @k, (@h - y1) * @k, x2 * @k, (@h - y2) * @k));
1214 out(sprintf('%.2f %.2f m %.2f %.2f l S', x1 * @k, (@h - y1) * @k, x2 * @k, (@h - y2) * @k));
1215 end
1215 end
1216 alias_method :line, :Line
1216 alias_method :line, :Line
1217
1217
1218 def Circle(mid_x, mid_y, radius, style='')
1218 def Circle(mid_x, mid_y, radius, style='')
1219 mid_y = (@h-mid_y)*@k
1219 mid_y = (@h-mid_y)*@k
1220 out(sprintf("q\n")) # postscript content in pdf
1220 out(sprintf("q\n")) # postscript content in pdf
1221 # init line type etc. with /GSD gs G g (grey) RG rg (RGB) w=line witdh etc.
1221 # init line type etc. with /GSD gs G g (grey) RG rg (RGB) w=line witdh etc.
1222 out(sprintf("1 j\n")) # line join
1222 out(sprintf("1 j\n")) # line join
1223 # translate ("move") circle to mid_y, mid_y
1223 # translate ("move") circle to mid_y, mid_y
1224 out(sprintf("1 0 0 1 %f %f cm", mid_x, mid_y))
1224 out(sprintf("1 0 0 1 %f %f cm", mid_x, mid_y))
1225 kappa = 0.5522847498307933984022516322796
1225 kappa = 0.5522847498307933984022516322796
1226 # Quadrant 1
1226 # Quadrant 1
1227 x_s = 0.0 # 12 o'clock
1227 x_s = 0.0 # 12 o'clock
1228 y_s = 0.0 + radius
1228 y_s = 0.0 + radius
1229 x_e = 0.0 + radius # 3 o'clock
1229 x_e = 0.0 + radius # 3 o'clock
1230 y_e = 0.0
1230 y_e = 0.0
1231 out(sprintf("%f %f m\n", x_s, y_s)) # move to 12 o'clock
1231 out(sprintf("%f %f m\n", x_s, y_s)) # move to 12 o'clock
1232 # cubic bezier control point 1, start height and kappa * radius to the right
1232 # cubic bezier control point 1, start height and kappa * radius to the right
1233 bx_e1 = x_s + (radius * kappa)
1233 bx_e1 = x_s + (radius * kappa)
1234 by_e1 = y_s
1234 by_e1 = y_s
1235 # cubic bezier control point 2, end and kappa * radius above
1235 # cubic bezier control point 2, end and kappa * radius above
1236 bx_e2 = x_e
1236 bx_e2 = x_e
1237 by_e2 = y_e + (radius * kappa)
1237 by_e2 = y_e + (radius * kappa)
1238 # draw cubic bezier from current point to x_e/y_e with bx_e1/by_e1 and bx_e2/by_e2 as bezier control points
1238 # draw cubic bezier from current point to x_e/y_e with bx_e1/by_e1 and bx_e2/by_e2 as bezier control points
1239 out(sprintf("%f %f %f %f %f %f c\n", bx_e1, by_e1, bx_e2, by_e2, x_e, y_e))
1239 out(sprintf("%f %f %f %f %f %f c\n", bx_e1, by_e1, bx_e2, by_e2, x_e, y_e))
1240 # Quadrant 2
1240 # Quadrant 2
1241 x_s = x_e
1241 x_s = x_e
1242 y_s = y_e # 3 o'clock
1242 y_s = y_e # 3 o'clock
1243 x_e = 0.0
1243 x_e = 0.0
1244 y_e = 0.0 - radius # 6 o'clock
1244 y_e = 0.0 - radius # 6 o'clock
1245 bx_e1 = x_s # cubic bezier point 1
1245 bx_e1 = x_s # cubic bezier point 1
1246 by_e1 = y_s - (radius * kappa)
1246 by_e1 = y_s - (radius * kappa)
1247 bx_e2 = x_e + (radius * kappa) # cubic bezier point 2
1247 bx_e2 = x_e + (radius * kappa) # cubic bezier point 2
1248 by_e2 = y_e
1248 by_e2 = y_e
1249 out(sprintf("%f %f %f %f %f %f c\n", bx_e1, by_e1, bx_e2, by_e2, x_e, y_e))
1249 out(sprintf("%f %f %f %f %f %f c\n", bx_e1, by_e1, bx_e2, by_e2, x_e, y_e))
1250 # Quadrant 3
1250 # Quadrant 3
1251 x_s = x_e
1251 x_s = x_e
1252 y_s = y_e # 6 o'clock
1252 y_s = y_e # 6 o'clock
1253 x_e = 0.0 - radius
1253 x_e = 0.0 - radius
1254 y_e = 0.0 # 9 o'clock
1254 y_e = 0.0 # 9 o'clock
1255 bx_e1 = x_s - (radius * kappa) # cubic bezier point 1
1255 bx_e1 = x_s - (radius * kappa) # cubic bezier point 1
1256 by_e1 = y_s
1256 by_e1 = y_s
1257 bx_e2 = x_e # cubic bezier point 2
1257 bx_e2 = x_e # cubic bezier point 2
1258 by_e2 = y_e - (radius * kappa)
1258 by_e2 = y_e - (radius * kappa)
1259 out(sprintf("%f %f %f %f %f %f c\n", bx_e1, by_e1, bx_e2, by_e2, x_e, y_e))
1259 out(sprintf("%f %f %f %f %f %f c\n", bx_e1, by_e1, bx_e2, by_e2, x_e, y_e))
1260 # Quadrant 4
1260 # Quadrant 4
1261 x_s = x_e
1261 x_s = x_e
1262 y_s = y_e # 9 o'clock
1262 y_s = y_e # 9 o'clock
1263 x_e = 0.0
1263 x_e = 0.0
1264 y_e = 0.0 + radius # 12 o'clock
1264 y_e = 0.0 + radius # 12 o'clock
1265 bx_e1 = x_s # cubic bezier point 1
1265 bx_e1 = x_s # cubic bezier point 1
1266 by_e1 = y_s + (radius * kappa)
1266 by_e1 = y_s + (radius * kappa)
1267 bx_e2 = x_e - (radius * kappa) # cubic bezier point 2
1267 bx_e2 = x_e - (radius * kappa) # cubic bezier point 2
1268 by_e2 = y_e
1268 by_e2 = y_e
1269 out(sprintf("%f %f %f %f %f %f c\n", bx_e1, by_e1, bx_e2, by_e2, x_e, y_e))
1269 out(sprintf("%f %f %f %f %f %f c\n", bx_e1, by_e1, bx_e2, by_e2, x_e, y_e))
1270 if style=='F'
1270 if style=='F'
1271 op='f'
1271 op='f'
1272 elsif style=='FD' or style=='DF'
1272 elsif style=='FD' or style=='DF'
1273 op='b'
1273 op='b'
1274 else
1274 else
1275 op='s'
1275 op='s'
1276 end
1276 end
1277 out(sprintf("#{op}\n")) # stroke circle, do not fill and close path
1277 out(sprintf("#{op}\n")) # stroke circle, do not fill and close path
1278 # for filling etc. b, b*, f, f*
1278 # for filling etc. b, b*, f, f*
1279 out(sprintf("Q\n")) # finish postscript in PDF
1279 out(sprintf("Q\n")) # finish postscript in PDF
1280 end
1280 end
1281 alias_method :circle, :Circle
1281 alias_method :circle, :Circle
1282
1282
1283 #
1283 #
1284 # Outputs a rectangle. It can be drawn (border only), filled (with no border) or both.
1284 # Outputs a rectangle. It can be drawn (border only), filled (with no border) or both.
1285 # @param float :x Abscissa of upper-left corner
1285 # @param float :x Abscissa of upper-left corner
1286 # @param float :y Ordinate of upper-left corner
1286 # @param float :y Ordinate of upper-left corner
1287 # @param float :w Width
1287 # @param float :w Width
1288 # @param float :h Height
1288 # @param float :h Height
1289 # @param string :style Style of rendering. Possible values are:<ul><li>D or empty string: draw (default)</li><li>F: fill</li><li>DF or FD: draw and fill</li></ul>
1289 # @param string :style Style of rendering. Possible values are:<ul><li>D or empty string: draw (default)</li><li>F: fill</li><li>DF or FD: draw and fill</li></ul>
1290 # @since 1.0
1290 # @since 1.0
1291 # @see SetLineWidth(), SetDrawColor(), SetFillColor()
1291 # @see SetLineWidth(), SetDrawColor(), SetFillColor()
1292 #
1292 #
1293 def Rect(x, y, w, h, style='')
1293 def Rect(x, y, w, h, style='')
1294 #Draw a rectangle
1294 #Draw a rectangle
1295 if (style=='F')
1295 if (style=='F')
1296 op='f';
1296 op='f';
1297 elsif (style=='FD' or style=='DF')
1297 elsif (style=='FD' or style=='DF')
1298 op='B';
1298 op='B';
1299 else
1299 else
1300 op='S';
1300 op='S';
1301 end
1301 end
1302 out(sprintf('%.2f %.2f %.2f %.2f re %s', x * @k, (@h - y) * @k, w * @k, -h * @k, op));
1302 out(sprintf('%.2f %.2f %.2f %.2f re %s', x * @k, (@h - y) * @k, w * @k, -h * @k, op));
1303 end
1303 end
1304 alias_method :rect, :Rect
1304 alias_method :rect, :Rect
1305
1305
1306 #
1306 #
1307 # Imports a TrueType or Type1 font and makes it available. It is necessary to generate a font definition file first with the makefont.rb utility. The definition file (and the font file itself when embedding) must be present either in the current directory or in the one indicated by FPDF_FONTPATH if the constant is defined. If it could not be found, the error "Could not include font definition file" is generated.
1307 # Imports a TrueType or Type1 font and makes it available. It is necessary to generate a font definition file first with the makefont.rb utility. The definition file (and the font file itself when embedding) must be present either in the current directory or in the one indicated by FPDF_FONTPATH if the constant is defined. If it could not be found, the error "Could not include font definition file" is generated.
1308 # Support UTF-8 Unicode [Nicola Asuni, 2005-01-02].
1308 # Support UTF-8 Unicode [Nicola Asuni, 2005-01-02].
1309 # <b>Example</b>:<br />
1309 # <b>Example</b>:<br />
1310 # <pre>
1310 # <pre>
1311 # :pdf->AddFont('Comic','I');
1311 # :pdf->AddFont('Comic','I');
1312 # # is equivalent to:
1312 # # is equivalent to:
1313 # :pdf->AddFont('Comic','I','comici.rb');
1313 # :pdf->AddFont('Comic','I','comici.rb');
1314 # </pre>
1314 # </pre>
1315 # @param string :family Font family. The name can be chosen arbitrarily. If it is a standard family name, it will override the corresponding font.
1315 # @param string :family Font family. The name can be chosen arbitrarily. If it is a standard family name, it will override the corresponding font.
1316 # @param string :style Font style. Possible values are (case insensitive):<ul><li>empty string: regular (default)</li><li>B: bold</li><li>I: italic</li><li>BI or IB: bold italic</li></ul>
1316 # @param string :style Font style. Possible values are (case insensitive):<ul><li>empty string: regular (default)</li><li>B: bold</li><li>I: italic</li><li>BI or IB: bold italic</li></ul>
1317 # @param string :file The font definition file. By default, the name is built from the family and style, in lower case with no space.
1317 # @param string :file The font definition file. By default, the name is built from the family and style, in lower case with no space.
1318 # @since 1.5
1318 # @since 1.5
1319 # @see SetFont()
1319 # @see SetFont()
1320 #
1320 #
1321 def AddFont(family, style='', file='')
1321 def AddFont(family, style='', file='')
1322 if (family.empty?)
1322 if (family.empty?)
1323 return;
1323 return;
1324 end
1324 end
1325
1325
1326 #Add a TrueType or Type1 font
1326 #Add a TrueType or Type1 font
1327 family = family.downcase
1327 family = family.downcase
1328 if ((!@is_unicode) and (family == 'arial'))
1328 if ((!@is_unicode) and (family == 'arial'))
1329 family = 'helvetica';
1329 family = 'helvetica';
1330 end
1330 end
1331
1331
1332 style=style.upcase
1332 style=style.upcase
1333 style=style.gsub('U','');
1333 style=style.gsub('U','');
1334 style=style.gsub('D','');
1334 style=style.gsub('D','');
1335 if (style == 'IB')
1335 if (style == 'IB')
1336 style = 'BI';
1336 style = 'BI';
1337 end
1337 end
1338
1338
1339 fontkey = family + style;
1339 fontkey = family + style;
1340 # check if the font has been already added
1340 # check if the font has been already added
1341 if !@fonts[fontkey].nil?
1341 if !@fonts[fontkey].nil?
1342 return;
1342 return;
1343 end
1343 end
1344
1344
1345 if (file=='')
1345 if (file=='')
1346 file = family.gsub(' ', '') + style.downcase + '.rb';
1346 file = family.gsub(' ', '') + style.downcase + '.rb';
1347 end
1347 end
1348 font_file_name = getfontpath(file)
1348 font_file_name = getfontpath(file)
1349 if (font_file_name.nil?)
1349 if (font_file_name.nil?)
1350 # try to load the basic file without styles
1350 # try to load the basic file without styles
1351 file = family.gsub(' ', '') + '.rb';
1351 file = family.gsub(' ', '') + '.rb';
1352 font_file_name = getfontpath(file)
1352 font_file_name = getfontpath(file)
1353 end
1353 end
1354 if font_file_name.nil?
1354 if font_file_name.nil?
1355 Error("Could not find font #{file}.")
1355 Error("Could not find font #{file}.")
1356 end
1356 end
1357 require(getfontpath(file))
1357 require(getfontpath(file))
1358 font_desc = TCPDFFontDescriptor.font(file)
1358 font_desc = TCPDFFontDescriptor.font(file)
1359
1359
1360 if (font_desc[:name].nil? and @@fpdf_charwidths.nil?)
1360 if (font_desc[:name].nil? and @@fpdf_charwidths.nil?)
1361 Error('Could not include font definition file');
1361 Error('Could not include font definition file');
1362 end
1362 end
1363
1363
1364 i = @fonts.length+1;
1364 i = @fonts.length+1;
1365 if (@is_unicode)
1365 if (@is_unicode)
1366 @fonts[fontkey] = {'i' => i, 'type' => font_desc[:type], 'name' => font_desc[:name], 'desc' => font_desc[:desc], 'up' => font_desc[:up], 'ut' => font_desc[:ut], 'cw' => font_desc[:cw], 'enc' => font_desc[:enc], 'file' => font_desc[:file], 'ctg' => font_desc[:ctg], 'cMap' => font_desc[:cMap], 'registry' => font_desc[:registry]}
1366 @fonts[fontkey] = {'i' => i, 'type' => font_desc[:type], 'name' => font_desc[:name], 'desc' => font_desc[:desc], 'up' => font_desc[:up], 'ut' => font_desc[:ut], 'cw' => font_desc[:cw], 'enc' => font_desc[:enc], 'file' => font_desc[:file], 'ctg' => font_desc[:ctg], 'cMap' => font_desc[:cMap], 'registry' => font_desc[:registry]}
1367 @@fpdf_charwidths[fontkey] = font_desc[:cw];
1367 @@fpdf_charwidths[fontkey] = font_desc[:cw];
1368 else
1368 else
1369 @fonts[fontkey]={'i' => i, 'type'=>'core', 'name'=>@core_fonts[fontkey], 'up'=>-100, 'ut'=>50, 'cw' => font_desc[:cw]}
1369 @fonts[fontkey]={'i' => i, 'type'=>'core', 'name'=>@core_fonts[fontkey], 'up'=>-100, 'ut'=>50, 'cw' => font_desc[:cw]}
1370 @@fpdf_charwidths[fontkey] = font_desc[:cw];
1370 @@fpdf_charwidths[fontkey] = font_desc[:cw];
1371 end
1371 end
1372
1372
1373 if (!font_desc[:diff].nil? and (!font_desc[:diff].empty?))
1373 if (!font_desc[:diff].nil? and (!font_desc[:diff].empty?))
1374 #Search existing encodings
1374 #Search existing encodings
1375 d=0;
1375 d=0;
1376 nb=@diffs.length;
1376 nb=@diffs.length;
1377 1.upto(nb) do |i|
1377 1.upto(nb) do |i|
1378 if (@diffs[i]== font_desc[:diff])
1378 if (@diffs[i]== font_desc[:diff])
1379 d = i;
1379 d = i;
1380 break;
1380 break;
1381 end
1381 end
1382 end
1382 end
1383 if (d==0)
1383 if (d==0)
1384 d = nb+1;
1384 d = nb+1;
1385 @diffs[d] = font_desc[:diff];
1385 @diffs[d] = font_desc[:diff];
1386 end
1386 end
1387 @fonts[fontkey]['diff'] = d;
1387 @fonts[fontkey]['diff'] = d;
1388 end
1388 end
1389 if (font_desc[:file] and font_desc[:file].length > 0)
1389 if (font_desc[:file] and font_desc[:file].length > 0)
1390 if (font_desc[:type] == "TrueType") or (font_desc[:type] == "TrueTypeUnicode")
1390 if (font_desc[:type] == "TrueType") or (font_desc[:type] == "TrueTypeUnicode")
1391 @font_files[font_desc[:file]] = {'length1' => font_desc[:originalsize]}
1391 @font_files[font_desc[:file]] = {'length1' => font_desc[:originalsize]}
1392 else
1392 else
1393 @font_files[font_desc[:file]] = {'length1' => font_desc[:size1], 'length2' => font_desc[:size2]}
1393 @font_files[font_desc[:file]] = {'length1' => font_desc[:size1], 'length2' => font_desc[:size2]}
1394 end
1394 end
1395 end
1395 end
1396 end
1396 end
1397 alias_method :add_font, :AddFont
1397 alias_method :add_font, :AddFont
1398
1398
1399 #
1399 #
1400 # Sets the font used to print character strings. It is mandatory to call this method at least once before printing text or the resulting document would not be valid.
1400 # Sets the font used to print character strings. It is mandatory to call this method at least once before printing text or the resulting document would not be valid.
1401 # The font can be either a standard one or a font added via the AddFont() method. Standard fonts use Windows encoding cp1252 (Western Europe).
1401 # The font can be either a standard one or a font added via the AddFont() method. Standard fonts use Windows encoding cp1252 (Western Europe).
1402 # The method can be called before the first page is created and the font is retained from page to page.
1402 # The method can be called before the first page is created and the font is retained from page to page.
1403 # If you just wish to change the current font size, it is simpler to call SetFontSize().
1403 # If you just wish to change the current font size, it is simpler to call SetFontSize().
1404 # Note: for the standard fonts, the font metric files must be accessible. There are three possibilities for this:<ul><li>They are in the current directory (the one where the running script lies)</li><li>They are in one of the directories defined by the include_path parameter</li><li>They are in the directory defined by the FPDF_FONTPATH constant</li></ul><br />
1404 # Note: for the standard fonts, the font metric files must be accessible. There are three possibilities for this:<ul><li>They are in the current directory (the one where the running script lies)</li><li>They are in one of the directories defined by the include_path parameter</li><li>They are in the directory defined by the FPDF_FONTPATH constant</li></ul><br />
1405 # Example for the last case (note the trailing slash):<br />
1405 # Example for the last case (note the trailing slash):<br />
1406 # <pre>
1406 # <pre>
1407 # define('FPDF_FONTPATH','/home/www/font/');
1407 # define('FPDF_FONTPATH','/home/www/font/');
1408 # require('tcpdf.rb');
1408 # require('tcpdf.rb');
1409 #
1409 #
1410 # #Times regular 12
1410 # #Times regular 12
1411 # :pdf->SetFont('Times');
1411 # :pdf->SetFont('Times');
1412 # #Arial bold 14
1412 # #Arial bold 14
1413 # :pdf->SetFont('Arial','B',14);
1413 # :pdf->SetFont('Arial','B',14);
1414 # #Removes bold
1414 # #Removes bold
1415 # :pdf->SetFont('');
1415 # :pdf->SetFont('');
1416 # #Times bold, italic and underlined 14
1416 # #Times bold, italic and underlined 14
1417 # :pdf->SetFont('Times','BIUD');
1417 # :pdf->SetFont('Times','BIUD');
1418 # </pre><br />
1418 # </pre><br />
1419 # If the file corresponding to the requested font is not found, the error "Could not include font metric file" is generated.
1419 # If the file corresponding to the requested font is not found, the error "Could not include font metric file" is generated.
1420 # @param string :family Family font. It can be either a name defined by AddFont() or one of the standard families (case insensitive):<ul><li>Courier (fixed-width)</li><li>Helvetica or Arial (synonymous; sans serif)</li><li>Times (serif)</li><li>Symbol (symbolic)</li><li>ZapfDingbats (symbolic)</li></ul>It is also possible to pass an empty string. In that case, the current family is retained.
1420 # @param string :family Family font. It can be either a name defined by AddFont() or one of the standard families (case insensitive):<ul><li>Courier (fixed-width)</li><li>Helvetica or Arial (synonymous; sans serif)</li><li>Times (serif)</li><li>Symbol (symbolic)</li><li>ZapfDingbats (symbolic)</li></ul>It is also possible to pass an empty string. In that case, the current family is retained.
1421 # @param string :style Font style. Possible values are (case insensitive):<ul><li>empty string: regular</li><li>B: bold</li><li>I: italic</li><li>U: underline</li></ul>or any combination. The default value is regular. Bold and italic styles do not apply to Symbol and ZapfDingbats
1421 # @param string :style Font style. Possible values are (case insensitive):<ul><li>empty string: regular</li><li>B: bold</li><li>I: italic</li><li>U: underline</li></ul>or any combination. The default value is regular. Bold and italic styles do not apply to Symbol and ZapfDingbats
1422 # @param float :size Font size in points. The default value is the current size. If no size has been specified since the beginning of the document, the value taken is 12
1422 # @param float :size Font size in points. The default value is the current size. If no size has been specified since the beginning of the document, the value taken is 12
1423 # @since 1.0
1423 # @since 1.0
1424 # @see AddFont(), SetFontSize(), Cell(), MultiCell(), Write()
1424 # @see AddFont(), SetFontSize(), Cell(), MultiCell(), Write()
1425 #
1425 #
1426 def SetFont(family, style='', size=0)
1426 def SetFont(family, style='', size=0)
1427 # save previous values
1427 # save previous values
1428 @prevfont_family = @font_family;
1428 @prevfont_family = @font_family;
1429 @prevfont_style = @font_style;
1429 @prevfont_style = @font_style;
1430
1430
1431 family=family.downcase;
1431 family=family.downcase;
1432 if (family=='')
1432 if (family=='')
1433 family=@font_family;
1433 family=@font_family;
1434 end
1434 end
1435 if ((!@is_unicode) and (family == 'arial'))
1435 if ((!@is_unicode) and (family == 'arial'))
1436 family = 'helvetica';
1436 family = 'helvetica';
1437 elsif ((family=="symbol") or (family=="zapfdingbats"))
1437 elsif ((family=="symbol") or (family=="zapfdingbats"))
1438 style='';
1438 style='';
1439 end
1439 end
1440
1440
1441 style=style.upcase;
1441 style=style.upcase;
1442
1442
1443 if (style.include?('U'))
1443 if (style.include?('U'))
1444 @underline=true;
1444 @underline=true;
1445 style= style.gsub('U','');
1445 style= style.gsub('U','');
1446 else
1446 else
1447 @underline=false;
1447 @underline=false;
1448 end
1448 end
1449 if (style.include?('D'))
1449 if (style.include?('D'))
1450 @deleted=true;
1450 @deleted=true;
1451 style= style.gsub('D','');
1451 style= style.gsub('D','');
1452 else
1452 else
1453 @deleted=false;
1453 @deleted=false;
1454 end
1454 end
1455 if (style=='IB')
1455 if (style=='IB')
1456 style='BI';
1456 style='BI';
1457 end
1457 end
1458 if (size==0)
1458 if (size==0)
1459 size=@font_size_pt;
1459 size=@font_size_pt;
1460 end
1460 end
1461
1461
1462 # try to add font (if not already added)
1462 # try to add font (if not already added)
1463 AddFont(family, style);
1463 AddFont(family, style);
1464
1464
1465 #Test if font is already selected
1465 #Test if font is already selected
1466 if ((@font_family == family) and (@font_style == style) and (@font_size_pt == size))
1466 if ((@font_family == family) and (@font_style == style) and (@font_size_pt == size))
1467 return;
1467 return;
1468 end
1468 end
1469
1469
1470 fontkey = family + style;
1470 fontkey = family + style;
1471 style = '' if (@fonts[fontkey].nil? and !@fonts[family].nil?)
1471 style = '' if (@fonts[fontkey].nil? and !@fonts[family].nil?)
1472
1472
1473 #Test if used for the first time
1473 #Test if used for the first time
1474 if (@fonts[fontkey].nil?)
1474 if (@fonts[fontkey].nil?)
1475 #Check if one of the standard fonts
1475 #Check if one of the standard fonts
1476 if (!@core_fonts[fontkey].nil?)
1476 if (!@core_fonts[fontkey].nil?)
1477 if @@fpdf_charwidths[fontkey].nil?
1477 if @@fpdf_charwidths[fontkey].nil?
1478 #Load metric file
1478 #Load metric file
1479 file = family;
1479 file = family;
1480 if ((family!='symbol') and (family!='zapfdingbats'))
1480 if ((family!='symbol') and (family!='zapfdingbats'))
1481 file += style.downcase;
1481 file += style.downcase;
1482 end
1482 end
1483 if (getfontpath(file + '.rb').nil?)
1483 if (getfontpath(file + '.rb').nil?)
1484 # try to load the basic file without styles
1484 # try to load the basic file without styles
1485 file = family;
1485 file = family;
1486 fontkey = family;
1486 fontkey = family;
1487 end
1487 end
1488 require(getfontpath(file + '.rb'));
1488 require(getfontpath(file + '.rb'));
1489 font_desc = TCPDFFontDescriptor.font(file)
1489 font_desc = TCPDFFontDescriptor.font(file)
1490 if ((@is_unicode and ctg.nil?) or ((!@is_unicode) and (@@fpdf_charwidths[fontkey].nil?)) )
1490 if ((@is_unicode and ctg.nil?) or ((!@is_unicode) and (@@fpdf_charwidths[fontkey].nil?)) )
1491 Error("Could not include font metric file [" + fontkey + "]: " + getfontpath(file + ".rb"));
1491 Error("Could not include font metric file [" + fontkey + "]: " + getfontpath(file + ".rb"));
1492 end
1492 end
1493 end
1493 end
1494 i = @fonts.length + 1;
1494 i = @fonts.length + 1;
1495
1495
1496 if (@is_unicode)
1496 if (@is_unicode)
1497 @fonts[fontkey] = {'i' => i, 'type' => font_desc[:type], 'name' => font_desc[:name], 'desc' => font_desc[:desc], 'up' => font_desc[:up], 'ut' => font_desc[:ut], 'cw' => font_desc[:cw], 'enc' => font_desc[:enc], 'file' => font_desc[:file], 'ctg' => font_desc[:ctg]}
1497 @fonts[fontkey] = {'i' => i, 'type' => font_desc[:type], 'name' => font_desc[:name], 'desc' => font_desc[:desc], 'up' => font_desc[:up], 'ut' => font_desc[:ut], 'cw' => font_desc[:cw], 'enc' => font_desc[:enc], 'file' => font_desc[:file], 'ctg' => font_desc[:ctg]}
1498 @@fpdf_charwidths[fontkey] = font_desc[:cw];
1498 @@fpdf_charwidths[fontkey] = font_desc[:cw];
1499 else
1499 else
1500 @fonts[fontkey] = {'i' => i, 'type'=>'core', 'name'=>@core_fonts[fontkey], 'up'=>-100, 'ut'=>50, 'cw' => font_desc[:cw]}
1500 @fonts[fontkey] = {'i' => i, 'type'=>'core', 'name'=>@core_fonts[fontkey], 'up'=>-100, 'ut'=>50, 'cw' => font_desc[:cw]}
1501 @@fpdf_charwidths[fontkey] = font_desc[:cw];
1501 @@fpdf_charwidths[fontkey] = font_desc[:cw];
1502 end
1502 end
1503 else
1503 else
1504 Error('Undefined font: ' + family + ' ' + style);
1504 Error('Undefined font: ' + family + ' ' + style);
1505 end
1505 end
1506 end
1506 end
1507 #Select it
1507 #Select it
1508 @font_family = family;
1508 @font_family = family;
1509 @font_style = style;
1509 @font_style = style;
1510 @font_size_pt = size;
1510 @font_size_pt = size;
1511 @font_size = size / @k;
1511 @font_size = size / @k;
1512 @current_font = @fonts[fontkey]; # was & may need deep copy?
1512 @current_font = @fonts[fontkey]; # was & may need deep copy?
1513 if (@page>0)
1513 if (@page>0)
1514 out(sprintf('BT /F%d %.2f Tf ET', @current_font['i'], @font_size_pt));
1514 out(sprintf('BT /F%d %.2f Tf ET', @current_font['i'], @font_size_pt));
1515 end
1515 end
1516 end
1516 end
1517 alias_method :set_font, :SetFont
1517 alias_method :set_font, :SetFont
1518
1518
1519 #
1519 #
1520 # Defines the size of the current font.
1520 # Defines the size of the current font.
1521 # @param float :size The size (in points)
1521 # @param float :size The size (in points)
1522 # @since 1.0
1522 # @since 1.0
1523 # @see SetFont()
1523 # @see SetFont()
1524 #
1524 #
1525 def SetFontSize(size)
1525 def SetFontSize(size)
1526 #Set font size in points
1526 #Set font size in points
1527 if (@font_size_pt== size)
1527 if (@font_size_pt== size)
1528 return;
1528 return;
1529 end
1529 end
1530 @font_size_pt = size;
1530 @font_size_pt = size;
1531 @font_size = size.to_f / @k;
1531 @font_size = size.to_f / @k;
1532 if (@page > 0)
1532 if (@page > 0)
1533 out(sprintf('BT /F%d %.2f Tf ET', @current_font['i'], @font_size_pt));
1533 out(sprintf('BT /F%d %.2f Tf ET', @current_font['i'], @font_size_pt));
1534 end
1534 end
1535 end
1535 end
1536 alias_method :set_font_size, :SetFontSize
1536 alias_method :set_font_size, :SetFontSize
1537
1537
1538 #
1538 #
1539 # Creates a new internal link and returns its identifier. An internal link is a clickable area which directs to another place within the document.<br />
1539 # Creates a new internal link and returns its identifier. An internal link is a clickable area which directs to another place within the document.<br />
1540 # The identifier can then be passed to Cell(), Write(), Image() or Link(). The destination is defined with SetLink().
1540 # The identifier can then be passed to Cell(), Write(), Image() or Link(). The destination is defined with SetLink().
1541 # @since 1.5
1541 # @since 1.5
1542 # @see Cell(), Write(), Image(), Link(), SetLink()
1542 # @see Cell(), Write(), Image(), Link(), SetLink()
1543 #
1543 #
1544 def AddLink()
1544 def AddLink()
1545 #Create a new internal link
1545 #Create a new internal link
1546 n=@links.length+1;
1546 n=@links.length+1;
1547 @links[n]=[0,0];
1547 @links[n]=[0,0];
1548 return n;
1548 return n;
1549 end
1549 end
1550 alias_method :add_link, :AddLink
1550 alias_method :add_link, :AddLink
1551
1551
1552 #
1552 #
1553 # Defines the page and position a link points to
1553 # Defines the page and position a link points to
1554 # @param int :link The link identifier returned by AddLink()
1554 # @param int :link The link identifier returned by AddLink()
1555 # @param float :y Ordinate of target position; -1 indicates the current position. The default value is 0 (top of page)
1555 # @param float :y Ordinate of target position; -1 indicates the current position. The default value is 0 (top of page)
1556 # @param int :page Number of target page; -1 indicates the current page. This is the default value
1556 # @param int :page Number of target page; -1 indicates the current page. This is the default value
1557 # @since 1.5
1557 # @since 1.5
1558 # @see AddLink()
1558 # @see AddLink()
1559 #
1559 #
1560 def SetLink(link, y=0, page=-1)
1560 def SetLink(link, y=0, page=-1)
1561 #Set destination of internal link
1561 #Set destination of internal link
1562 if (y==-1)
1562 if (y==-1)
1563 y=@y;
1563 y=@y;
1564 end
1564 end
1565 if (page==-1)
1565 if (page==-1)
1566 page=@page;
1566 page=@page;
1567 end
1567 end
1568 @links[link] = [page, y]
1568 @links[link] = [page, y]
1569 end
1569 end
1570 alias_method :set_link, :SetLink
1570 alias_method :set_link, :SetLink
1571
1571
1572 #
1572 #
1573 # Puts a link on a rectangular area of the page. Text or image links are generally put via Cell(), Write() or Image(), but this method can be useful for instance to define a clickable area inside an image.
1573 # Puts a link on a rectangular area of the page. Text or image links are generally put via Cell(), Write() or Image(), but this method can be useful for instance to define a clickable area inside an image.
1574 # @param float :x Abscissa of the upper-left corner of the rectangle
1574 # @param float :x Abscissa of the upper-left corner of the rectangle
1575 # @param float :y Ordinate of the upper-left corner of the rectangle
1575 # @param float :y Ordinate of the upper-left corner of the rectangle
1576 # @param float :w Width of the rectangle
1576 # @param float :w Width of the rectangle
1577 # @param float :h Height of the rectangle
1577 # @param float :h Height of the rectangle
1578 # @param mixed :link URL or identifier returned by AddLink()
1578 # @param mixed :link URL or identifier returned by AddLink()
1579 # @since 1.5
1579 # @since 1.5
1580 # @see AddLink(), Cell(), Write(), Image()
1580 # @see AddLink(), Cell(), Write(), Image()
1581 #
1581 #
1582 def Link(x, y, w, h, link)
1582 def Link(x, y, w, h, link)
1583 #Put a link on the page
1583 #Put a link on the page
1584 @page_links ||= Array.new
1584 @page_links ||= Array.new
1585 @page_links[@page] ||= Array.new
1585 @page_links[@page] ||= Array.new
1586 @page_links[@page].push([x * @k, @h_pt - y * @k, w * @k, h*@k, link]);
1586 @page_links[@page].push([x * @k, @h_pt - y * @k, w * @k, h*@k, link]);
1587 end
1587 end
1588 alias_method :link, :Link
1588 alias_method :link, :Link
1589
1589
1590 #
1590 #
1591 # Prints a character string. The origin is on the left of the first charcter, on the baseline. This method allows to place a string precisely on the page, but it is usually easier to use Cell(), MultiCell() or Write() which are the standard methods to print text.
1591 # Prints a character string. The origin is on the left of the first charcter, on the baseline. This method allows to place a string precisely on the page, but it is usually easier to use Cell(), MultiCell() or Write() which are the standard methods to print text.
1592 # @param float :x Abscissa of the origin
1592 # @param float :x Abscissa of the origin
1593 # @param float :y Ordinate of the origin
1593 # @param float :y Ordinate of the origin
1594 # @param string :txt String to print
1594 # @param string :txt String to print
1595 # @since 1.0
1595 # @since 1.0
1596 # @see SetFont(), SetTextColor(), Cell(), MultiCell(), Write()
1596 # @see SetFont(), SetTextColor(), Cell(), MultiCell(), Write()
1597 #
1597 #
1598 def Text(x, y, txt)
1598 def Text(x, y, txt)
1599 #Output a string
1599 #Output a string
1600 s=sprintf('BT %.2f %.2f Td (%s) Tj ET', x * @k, (@h-y) * @k, escapetext(txt));
1600 s=sprintf('BT %.2f %.2f Td (%s) Tj ET', x * @k, (@h-y) * @k, escapetext(txt));
1601 if (@underline and (txt!=''))
1601 if (@underline and (txt!=''))
1602 s += ' ' + dolinetxt(x, y, txt);
1602 s += ' ' + dolinetxt(x, y, txt);
1603 end
1603 end
1604 if (@color_flag)
1604 if (@color_flag)
1605 s='q ' + @text_color + ' ' + s + ' Q';
1605 s='q ' + @text_color + ' ' + s + ' Q';
1606 end
1606 end
1607 out(s);
1607 out(s);
1608 end
1608 end
1609 alias_method :text, :Text
1609 alias_method :text, :Text
1610
1610
1611 #
1611 #
1612 # Whenever a page break condition is met, the method is called, and the break is issued or not depending on the returned value. The default implementation returns a value according to the mode selected by SetAutoPageBreak().<br />
1612 # Whenever a page break condition is met, the method is called, and the break is issued or not depending on the returned value. The default implementation returns a value according to the mode selected by SetAutoPageBreak().<br />
1613 # This method is called automatically and should not be called directly by the application.<br />
1613 # This method is called automatically and should not be called directly by the application.<br />
1614 # <b>Example:</b><br />
1614 # <b>Example:</b><br />
1615 # The method is overriden in an inherited class in order to obtain a 3 column layout:<br />
1615 # The method is overriden in an inherited class in order to obtain a 3 column layout:<br />
1616 # <pre>
1616 # <pre>
1617 # class PDF extends TCPDF {
1617 # class PDF extends TCPDF {
1618 # var :col=0;
1618 # var :col=0;
1619 #
1619 #
1620 # def SetCol(col)
1620 # def SetCol(col)
1621 # #Move position to a column
1621 # #Move position to a column
1622 # @col = col;
1622 # @col = col;
1623 # :x=10+:col*65;
1623 # :x=10+:col*65;
1624 # SetLeftMargin(x);
1624 # SetLeftMargin(x);
1625 # SetX(x);
1625 # SetX(x);
1626 # end
1626 # end
1627 #
1627 #
1628 # def AcceptPageBreak()
1628 # def AcceptPageBreak()
1629 # if (@col<2)
1629 # if (@col<2)
1630 # #Go to next column
1630 # #Go to next column
1631 # SetCol(@col+1);
1631 # SetCol(@col+1);
1632 # SetY(10);
1632 # SetY(10);
1633 # return false;
1633 # return false;
1634 # end
1634 # end
1635 # else
1635 # else
1636 # #Go back to first column and issue page break
1636 # #Go back to first column and issue page break
1637 # SetCol(0);
1637 # SetCol(0);
1638 # return true;
1638 # return true;
1639 # end
1639 # end
1640 # end
1640 # end
1641 # }
1641 # }
1642 #
1642 #
1643 # :pdf=new PDF();
1643 # :pdf=new PDF();
1644 # :pdf->Open();
1644 # :pdf->Open();
1645 # :pdf->AddPage();
1645 # :pdf->AddPage();
1646 # :pdf->SetFont('Arial','',12);
1646 # :pdf->SetFont('Arial','',12);
1647 # for(i=1;:i<=300;:i++)
1647 # for(i=1;:i<=300;:i++)
1648 # :pdf->Cell(0,5,"Line :i",0,1);
1648 # :pdf->Cell(0,5,"Line :i",0,1);
1649 # }
1649 # }
1650 # :pdf->Output();
1650 # :pdf->Output();
1651 # </pre>
1651 # </pre>
1652 # @return boolean
1652 # @return boolean
1653 # @since 1.4
1653 # @since 1.4
1654 # @see SetAutoPageBreak()
1654 # @see SetAutoPageBreak()
1655 #
1655 #
1656 def AcceptPageBreak()
1656 def AcceptPageBreak()
1657 #Accept automatic page break or not
1657 #Accept automatic page break or not
1658 return @auto_page_break;
1658 return @auto_page_break;
1659 end
1659 end
1660 alias_method :accept_page_break, :AcceptPageBreak
1660 alias_method :accept_page_break, :AcceptPageBreak
1661
1661
1662 def BreakThePage?(h)
1662 def BreakThePage?(h)
1663 if ((@y + h) > @page_break_trigger and !@in_footer and AcceptPageBreak())
1663 if ((@y + h) > @page_break_trigger and !@in_footer and AcceptPageBreak())
1664 true
1664 true
1665 else
1665 else
1666 false
1666 false
1667 end
1667 end
1668 end
1668 end
1669 alias_method :break_the_page?, :BreakThePage?
1669 alias_method :break_the_page?, :BreakThePage?
1670 #
1670 #
1671 # Prints a cell (rectangular area) with optional borders, background color and character string. The upper-left corner of the cell corresponds to the current position. The text can be aligned or centered. After the call, the current position moves to the right or to the next line. It is possible to put a link on the text.<br />
1671 # Prints a cell (rectangular area) with optional borders, background color and character string. The upper-left corner of the cell corresponds to the current position. The text can be aligned or centered. After the call, the current position moves to the right or to the next line. It is possible to put a link on the text.<br />
1672 # If automatic page breaking is enabled and the cell goes beyond the limit, a page break is done before outputting.
1672 # If automatic page breaking is enabled and the cell goes beyond the limit, a page break is done before outputting.
1673 # @param float :w Cell width. If 0, the cell extends up to the right margin.
1673 # @param float :w Cell width. If 0, the cell extends up to the right margin.
1674 # @param float :h Cell height. Default value: 0.
1674 # @param float :h Cell height. Default value: 0.
1675 # @param string :txt String to print. Default value: empty string.
1675 # @param string :txt String to print. Default value: empty string.
1676 # @param mixed :border Indicates if borders must be drawn around the cell. The value can be either a number:<ul><li>0: no border (default)</li><li>1: frame</li></ul>or a string containing some or all of the following characters (in any order):<ul><li>L: left</li><li>T: top</li><li>R: right</li><li>B: bottom</li></ul>
1676 # @param mixed :border Indicates if borders must be drawn around the cell. The value can be either a number:<ul><li>0: no border (default)</li><li>1: frame</li></ul>or a string containing some or all of the following characters (in any order):<ul><li>L: left</li><li>T: top</li><li>R: right</li><li>B: bottom</li></ul>
1677 # @param int :ln Indicates where the current position should go after the call. Possible values are:<ul><li>0: to the right</li><li>1: to the beginning of the next line</li><li>2: below</li></ul>
1677 # @param int :ln Indicates where the current position should go after the call. Possible values are:<ul><li>0: to the right</li><li>1: to the beginning of the next line</li><li>2: below</li></ul>
1678 # Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: 0.
1678 # Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: 0.
1679 # @param string :align Allows to center or align the text. Possible values are:<ul><li>L or empty string: left align (default value)</li><li>C: center</li><li>R: right align</li></ul>
1679 # @param string :align Allows to center or align the text. Possible values are:<ul><li>L or empty string: left align (default value)</li><li>C: center</li><li>R: right align</li></ul>
1680 # @param int :fill Indicates if the cell background must be painted (1) or transparent (0). Default value: 0.
1680 # @param int :fill Indicates if the cell background must be painted (1) or transparent (0). Default value: 0.
1681 # @param mixed :link URL or identifier returned by AddLink().
1681 # @param mixed :link URL or identifier returned by AddLink().
1682 # @since 1.0
1682 # @since 1.0
1683 # @see SetFont(), SetDrawColor(), SetFillColor(), SetTextColor(), SetLineWidth(), AddLink(), Ln(), MultiCell(), Write(), SetAutoPageBreak()
1683 # @see SetFont(), SetDrawColor(), SetFillColor(), SetTextColor(), SetLineWidth(), AddLink(), Ln(), MultiCell(), Write(), SetAutoPageBreak()
1684 #
1684 #
1685 def Cell(w, h=0, txt='', border=0, ln=0, align='', fill=0, link=nil)
1685 def Cell(w, h=0, txt='', border=0, ln=0, align='', fill=0, link=nil)
1686 #Output a cell
1686 #Output a cell
1687 k=@k;
1687 k=@k;
1688 if ((@y + h) > @page_break_trigger and !@in_footer and AcceptPageBreak())
1688 if ((@y + h) > @page_break_trigger and !@in_footer and AcceptPageBreak())
1689 #Automatic page break
1689 #Automatic page break
1690 if @pages[@page+1].nil?
1690 if @pages[@page+1].nil?
1691 x = @x;
1691 x = @x;
1692 ws = @ws;
1692 ws = @ws;
1693 if (ws > 0)
1693 if (ws > 0)
1694 @ws = 0;
1694 @ws = 0;
1695 out('0 Tw');
1695 out('0 Tw');
1696 end
1696 end
1697 AddPage(@cur_orientation);
1697 AddPage(@cur_orientation);
1698 @x = x;
1698 @x = x;
1699 if (ws > 0)
1699 if (ws > 0)
1700 @ws = ws;
1700 @ws = ws;
1701 out(sprintf('%.3f Tw', ws * k));
1701 out(sprintf('%.3f Tw', ws * k));
1702 end
1702 end
1703 else
1703 else
1704 @page += 1;
1704 @page += 1;
1705 @y=@t_margin;
1705 @y=@t_margin;
1706 end
1706 end
1707 end
1707 end
1708
1708
1709 if (w == 0)
1709 if (w == 0)
1710 w = @w - @r_margin - @x;
1710 w = @w - @r_margin - @x;
1711 end
1711 end
1712 s = '';
1712 s = '';
1713 if ((fill.to_i == 1) or (border.to_i == 1))
1713 if ((fill.to_i == 1) or (border.to_i == 1))
1714 if (fill.to_i == 1)
1714 if (fill.to_i == 1)
1715 op = (border.to_i == 1) ? 'B' : 'f';
1715 op = (border.to_i == 1) ? 'B' : 'f';
1716 else
1716 else
1717 op = 'S';
1717 op = 'S';
1718 end
1718 end
1719 s = sprintf('%.2f %.2f %.2f %.2f re %s ', @x * k, (@h - @y) * k, w * k, -h * k, op);
1719 s = sprintf('%.2f %.2f %.2f %.2f re %s ', @x * k, (@h - @y) * k, w * k, -h * k, op);
1720 end
1720 end
1721 if (border.is_a?(String))
1721 if (border.is_a?(String))
1722 x=@x;
1722 x=@x;
1723 y=@y;
1723 y=@y;
1724 if (border.include?('L'))
1724 if (border.include?('L'))
1725 s<<sprintf('%.2f %.2f m %.2f %.2f l S ', x*k,(@h-y)*k, x*k,(@h-(y+h))*k);
1725 s<<sprintf('%.2f %.2f m %.2f %.2f l S ', x*k,(@h-y)*k, x*k,(@h-(y+h))*k);
1726 end
1726 end
1727 if (border.include?('T'))
1727 if (border.include?('T'))
1728 s<<sprintf('%.2f %.2f m %.2f %.2f l S ', x*k,(@h-y)*k,(x+w)*k,(@h-y)*k);
1728 s<<sprintf('%.2f %.2f m %.2f %.2f l S ', x*k,(@h-y)*k,(x+w)*k,(@h-y)*k);
1729 end
1729 end
1730 if (border.include?('R'))
1730 if (border.include?('R'))
1731 s<<sprintf('%.2f %.2f m %.2f %.2f l S ',(x+w)*k,(@h-y)*k,(x+w)*k,(@h-(y+h))*k);
1731 s<<sprintf('%.2f %.2f m %.2f %.2f l S ',(x+w)*k,(@h-y)*k,(x+w)*k,(@h-(y+h))*k);
1732 end
1732 end
1733 if (border.include?('B'))
1733 if (border.include?('B'))
1734 s<<sprintf('%.2f %.2f m %.2f %.2f l S ', x*k,(@h-(y+h))*k,(x+w)*k,(@h-(y+h))*k);
1734 s<<sprintf('%.2f %.2f m %.2f %.2f l S ', x*k,(@h-(y+h))*k,(x+w)*k,(@h-(y+h))*k);
1735 end
1735 end
1736 end
1736 end
1737 if (txt != '')
1737 if (txt != '')
1738 width = GetStringWidth(txt);
1738 width = GetStringWidth(txt);
1739 if (align == 'R' || align == 'right')
1739 if (align == 'R' || align == 'right')
1740 dx = w - @c_margin - width;
1740 dx = w - @c_margin - width;
1741 elsif (align=='C' || align == 'center')
1741 elsif (align=='C' || align == 'center')
1742 dx = (w - width)/2;
1742 dx = (w - width)/2;
1743 else
1743 else
1744 dx = @c_margin;
1744 dx = @c_margin;
1745 end
1745 end
1746 if (@color_flag)
1746 if (@color_flag)
1747 s << 'q ' + @text_color + ' ';
1747 s << 'q ' + @text_color + ' ';
1748 end
1748 end
1749 txt2 = escapetext(txt);
1749 txt2 = escapetext(txt);
1750 s<<sprintf('BT %.2f %.2f Td (%s) Tj ET', (@x + dx) * k, (@h - (@y + 0.5 * h + 0.3 * @font_size)) * k, txt2);
1750 s<<sprintf('BT %.2f %.2f Td (%s) Tj ET', (@x + dx) * k, (@h - (@y + 0.5 * h + 0.3 * @font_size)) * k, txt2);
1751 if (@underline)
1751 if (@underline)
1752 s<<' ' + dolinetxt(@x + dx, @y + 0.5 * h + 0.3 * @font_size, txt);
1752 s<<' ' + dolinetxt(@x + dx, @y + 0.5 * h + 0.3 * @font_size, txt);
1753 end
1753 end
1754 if (@deleted)
1754 if (@deleted)
1755 s<<' ' + dolinetxt(@x + dx, @y + 0.3 * h + 0.2 * @font_size, txt);
1755 s<<' ' + dolinetxt(@x + dx, @y + 0.3 * h + 0.2 * @font_size, txt);
1756 end
1756 end
1757 if (@color_flag)
1757 if (@color_flag)
1758 s<<' Q';
1758 s<<' Q';
1759 end
1759 end
1760 if link && !link.empty?
1760 if link && !link.empty?
1761 Link(@x + dx, @y + 0.5 * h - 0.5 * @font_size, width, @font_size, link);
1761 Link(@x + dx, @y + 0.5 * h - 0.5 * @font_size, width, @font_size, link);
1762 end
1762 end
1763 end
1763 end
1764 if (s)
1764 if (s)
1765 out(s);
1765 out(s);
1766 end
1766 end
1767 @lasth = h;
1767 @lasth = h;
1768 if (ln.to_i>0)
1768 if (ln.to_i>0)
1769 # Go to next line
1769 # Go to next line
1770 @y += h;
1770 @y += h;
1771 if (ln == 1)
1771 if (ln == 1)
1772 @x = @l_margin;
1772 @x = @l_margin;
1773 end
1773 end
1774 else
1774 else
1775 @x += w;
1775 @x += w;
1776 end
1776 end
1777 end
1777 end
1778 alias_method :cell, :Cell
1778 alias_method :cell, :Cell
1779
1779
1780 #
1780 #
1781 # This method allows printing text with line breaks. They can be automatic (as soon as the text reaches the right border of the cell) or explicit (via the \n character). As many cells as necessary are output, one below the other.<br />
1781 # This method allows printing text with line breaks. They can be automatic (as soon as the text reaches the right border of the cell) or explicit (via the \n character). As many cells as necessary are output, one below the other.<br />
1782 # Text can be aligned, centered or justified. The cell block can be framed and the background painted.
1782 # Text can be aligned, centered or justified. The cell block can be framed and the background painted.
1783 # @param float :w Width of cells. If 0, they extend up to the right margin of the page.
1783 # @param float :w Width of cells. If 0, they extend up to the right margin of the page.
1784 # @param float :h Height of cells.
1784 # @param float :h Height of cells.
1785 # @param string :txt String to print
1785 # @param string :txt String to print
1786 # @param mixed :border Indicates if borders must be drawn around the cell block. The value can be either a number:<ul><li>0: no border (default)</li><li>1: frame</li></ul>or a string containing some or all of the following characters (in any order):<ul><li>L: left</li><li>T: top</li><li>R: right</li><li>B: bottom</li></ul>
1786 # @param mixed :border Indicates if borders must be drawn around the cell block. The value can be either a number:<ul><li>0: no border (default)</li><li>1: frame</li></ul>or a string containing some or all of the following characters (in any order):<ul><li>L: left</li><li>T: top</li><li>R: right</li><li>B: bottom</li></ul>
1787 # @param string :align Allows to center or align the text. Possible values are:<ul><li>L or empty string: left align</li><li>C: center</li><li>R: right align</li><li>J: justification (default value)</li></ul>
1787 # @param string :align Allows to center or align the text. Possible values are:<ul><li>L or empty string: left align</li><li>C: center</li><li>R: right align</li><li>J: justification (default value)</li></ul>
1788 # @param int :fill Indicates if the cell background must be painted (1) or transparent (0). Default value: 0.
1788 # @param int :fill Indicates if the cell background must be painted (1) or transparent (0). Default value: 0.
1789 # @param int :ln Indicates where the current position should go after the call. Possible values are:<ul><li>0: to the right</li><li>1: to the beginning of the next line [DEFAULT]</li><li>2: below</li></ul>
1789 # @param int :ln Indicates where the current position should go after the call. Possible values are:<ul><li>0: to the right</li><li>1: to the beginning of the next line [DEFAULT]</li><li>2: below</li></ul>
1790 # @since 1.3
1790 # @since 1.3
1791 # @see SetFont(), SetDrawColor(), SetFillColor(), SetTextColor(), SetLineWidth(), Cell(), Write(), SetAutoPageBreak()
1791 # @see SetFont(), SetDrawColor(), SetFillColor(), SetTextColor(), SetLineWidth(), Cell(), Write(), SetAutoPageBreak()
1792 #
1792 #
1793 def MultiCell(w, h, txt, border=0, align='J', fill=0, ln=1)
1793 def MultiCell(w, h, txt, border=0, align='J', fill=0, ln=1)
1794
1794
1795 # save current position
1795 # save current position
1796 prevx = @x;
1796 prevx = @x;
1797 prevy = @y;
1797 prevy = @y;
1798 prevpage = @page;
1798 prevpage = @page;
1799
1799
1800 #Output text with automatic or explicit line breaks
1800 #Output text with automatic or explicit line breaks
1801
1801
1802 if (w == 0)
1802 if (w == 0)
1803 w = @w - @r_margin - @x;
1803 w = @w - @r_margin - @x;
1804 end
1804 end
1805
1805
1806 wmax = (w - 2 * @c_margin);
1806 wmax = (w - 2 * @c_margin);
1807
1807
1808 s = txt.gsub("\r", ''); # remove carriage returns
1808 s = txt.gsub("\r", ''); # remove carriage returns
1809 nb = s.length;
1809 nb = s.length;
1810
1810
1811 b=0;
1811 b=0;
1812 if (border)
1812 if (border)
1813 if (border==1)
1813 if (border==1)
1814 border='LTRB';
1814 border='LTRB';
1815 b='LRT';
1815 b='LRT';
1816 b2='LR';
1816 b2='LR';
1817 elsif border.is_a?(String)
1817 elsif border.is_a?(String)
1818 b2='';
1818 b2='';
1819 if (border.include?('L'))
1819 if (border.include?('L'))
1820 b2<<'L';
1820 b2<<'L';
1821 end
1821 end
1822 if (border.include?('R'))
1822 if (border.include?('R'))
1823 b2<<'R';
1823 b2<<'R';
1824 end
1824 end
1825 b=(border.include?('T')) ? b2 + 'T' : b2;
1825 b=(border.include?('T')) ? b2 + 'T' : b2;
1826 end
1826 end
1827 end
1827 end
1828 sep=-1;
1828 sep=-1;
1829 to_index=0;
1829 to_index=0;
1830 from_j=0;
1830 from_j=0;
1831 l=0;
1831 l=0;
1832 ns=0;
1832 ns=0;
1833 nl=1;
1833 nl=1;
1834
1834
1835 while to_index < nb
1835 while to_index < nb
1836 #Get next character
1836 #Get next character
1837 c = s[to_index];
1837 c = s[to_index];
1838 if c == "\n"[0]
1838 if c == "\n"[0]
1839 #Explicit line break
1839 #Explicit line break
1840 if @ws > 0
1840 if @ws > 0
1841 @ws = 0
1841 @ws = 0
1842 out('0 Tw')
1842 out('0 Tw')
1843 end
1843 end
1844 #Ed Moss - change begin
1844 #Ed Moss - change begin
1845 end_i = to_index == 0 ? 0 : to_index - 1
1845 end_i = to_index == 0 ? 0 : to_index - 1
1846 # Changed from s[from_j..to_index] to fix bug reported by Hans Allis.
1846 # Changed from s[from_j..to_index] to fix bug reported by Hans Allis.
1847 from_j = to_index == 0 ? 1 : from_j
1847 from_j = to_index == 0 ? 1 : from_j
1848 Cell(w, h, s[from_j..end_i], b, 2, align, fill)
1848 Cell(w, h, s[from_j..end_i], b, 2, align, fill)
1849 #change end
1849 #change end
1850 to_index += 1
1850 to_index += 1
1851 sep=-1
1851 sep=-1
1852 from_j=to_index
1852 from_j=to_index
1853 l=0
1853 l=0
1854 ns=0
1854 ns=0
1855 nl += 1
1855 nl += 1
1856 b = b2 if border and nl==2
1856 b = b2 if border and nl==2
1857 next
1857 next
1858 end
1858 end
1859 if (c == " "[0])
1859 if (c == " "[0])
1860 sep = to_index;
1860 sep = to_index;
1861 ls = l;
1861 ls = l;
1862 ns += 1;
1862 ns += 1;
1863 end
1863 end
1864
1864
1865 l = GetStringWidth(s[from_j, to_index - from_j + 1]);
1865 l = GetStringWidth(s[from_j, to_index - from_j + 1]);
1866
1866
1867 if (l > wmax)
1867 if (l > wmax)
1868 #Automatic line break
1868 #Automatic line break
1869 if (sep == -1)
1869 if (sep == -1)
1870 if (to_index == from_j)
1870 if (to_index == from_j)
1871 to_index += 1;
1871 to_index += 1;
1872 end
1872 end
1873 if (@ws > 0)
1873 if (@ws > 0)
1874 @ws = 0;
1874 @ws = 0;
1875 out('0 Tw');
1875 out('0 Tw');
1876 end
1876 end
1877 Cell(w, h, s[from_j..to_index-1], b, 2, align, fill) # my FPDF version
1877 Cell(w, h, s[from_j..to_index-1], b, 2, align, fill) # my FPDF version
1878 else
1878 else
1879 if (align=='J' || align=='justify' || align=='justified')
1879 if (align=='J' || align=='justify' || align=='justified')
1880 @ws = (ns>1) ? (wmax-ls)/(ns-1) : 0;
1880 @ws = (ns>1) ? (wmax-ls)/(ns-1) : 0;
1881 out(sprintf('%.3f Tw', @ws * @k));
1881 out(sprintf('%.3f Tw', @ws * @k));
1882 end
1882 end
1883 Cell(w, h, s[from_j..sep], b, 2, align, fill);
1883 Cell(w, h, s[from_j..sep], b, 2, align, fill);
1884 to_index = sep + 1;
1884 to_index = sep + 1;
1885 end
1885 end
1886 sep=-1;
1886 sep=-1;
1887 from_j = to_index;
1887 from_j = to_index;
1888 l=0;
1888 l=0;
1889 ns=0;
1889 ns=0;
1890 nl += 1;
1890 nl += 1;
1891 if (border and (nl==2))
1891 if (border and (nl==2))
1892 b = b2;
1892 b = b2;
1893 end
1893 end
1894 else
1894 else
1895 to_index += 1;
1895 to_index += 1;
1896 end
1896 end
1897 end
1897 end
1898 #Last chunk
1898 #Last chunk
1899 if (@ws>0)
1899 if (@ws>0)
1900 @ws=0;
1900 @ws=0;
1901 out('0 Tw');
1901 out('0 Tw');
1902 end
1902 end
1903 if (border.is_a?(String) and border.include?('B'))
1903 if (border.is_a?(String) and border.include?('B'))
1904 b<<'B';
1904 b<<'B';
1905 end
1905 end
1906 Cell(w, h, s[from_j, to_index-from_j], b, 2, align, fill);
1906 Cell(w, h, s[from_j, to_index-from_j], b, 2, align, fill);
1907
1907
1908 # move cursor to specified position
1908 # move cursor to specified position
1909 # since 2007-03-03
1909 # since 2007-03-03
1910 if (ln == 1)
1910 if (ln == 1)
1911 # go to the beginning of the next line
1911 # go to the beginning of the next line
1912 @x = @l_margin;
1912 @x = @l_margin;
1913 elsif (ln == 0)
1913 elsif (ln == 0)
1914 # go to the top-right of the cell
1914 # go to the top-right of the cell
1915 @page = prevpage;
1915 @page = prevpage;
1916 @y = prevy;
1916 @y = prevy;
1917 @x = prevx + w;
1917 @x = prevx + w;
1918 elsif (ln == 2)
1918 elsif (ln == 2)
1919 # go to the bottom-left of the cell
1919 # go to the bottom-left of the cell
1920 @x = prevx;
1920 @x = prevx;
1921 end
1921 end
1922 end
1922 end
1923 alias_method :multi_cell, :MultiCell
1923 alias_method :multi_cell, :MultiCell
1924
1924
1925 #
1925 #
1926 # This method prints text from the current position. When the right margin is reached (or the \n character is met) a line break occurs and text continues from the left margin. Upon method exit, the current position is left just at the end of the text. It is possible to put a link on the text.<br />
1926 # This method prints text from the current position. When the right margin is reached (or the \n character is met) a line break occurs and text continues from the left margin. Upon method exit, the current position is left just at the end of the text. It is possible to put a link on the text.<br />
1927 # <b>Example:</b><br />
1927 # <b>Example:</b><br />
1928 # <pre>
1928 # <pre>
1929 # #Begin with regular font
1929 # #Begin with regular font
1930 # :pdf->SetFont('Arial','',14);
1930 # :pdf->SetFont('Arial','',14);
1931 # :pdf->Write(5,'Visit ');
1931 # :pdf->Write(5,'Visit ');
1932 # #Then put a blue underlined link
1932 # #Then put a blue underlined link
1933 # :pdf->SetTextColor(0,0,255);
1933 # :pdf->SetTextColor(0,0,255);
1934 # :pdf->SetFont('','U');
1934 # :pdf->SetFont('','U');
1935 # :pdf->Write(5,'www.tecnick.com','http://www.tecnick.com');
1935 # :pdf->Write(5,'www.tecnick.com','http://www.tecnick.com');
1936 # </pre>
1936 # </pre>
1937 # @param float :h Line height
1937 # @param float :h Line height
1938 # @param string :txt String to print
1938 # @param string :txt String to print
1939 # @param mixed :link URL or identifier returned by AddLink()
1939 # @param mixed :link URL or identifier returned by AddLink()
1940 # @param int :fill Indicates if the background must be painted (1) or transparent (0). Default value: 0.
1940 # @param int :fill Indicates if the background must be painted (1) or transparent (0). Default value: 0.
1941 # @since 1.5
1941 # @since 1.5
1942 # @see SetFont(), SetTextColor(), AddLink(), MultiCell(), SetAutoPageBreak()
1942 # @see SetFont(), SetTextColor(), AddLink(), MultiCell(), SetAutoPageBreak()
1943 #
1943 #
1944 def Write(h, txt, link=nil, fill=0)
1944 def Write(h, txt, link=nil, fill=0)
1945
1945
1946 #Output text in flowing mode
1946 #Output text in flowing mode
1947 w = @w - @r_margin - @x;
1947 w = @w - @r_margin - @x;
1948 wmax = (w - 2 * @c_margin);
1948 wmax = (w - 2 * @c_margin);
1949
1949
1950 s = txt.gsub("\r", '');
1950 s = txt.gsub("\r", '');
1951 nb = s.length;
1951 nb = s.length;
1952
1952
1953 # handle single space character
1953 # handle single space character
1954 if ((nb==1) and (s == " "))
1954 if ((nb==1) and (s == " "))
1955 @x += GetStringWidth(s);
1955 @x += GetStringWidth(s);
1956 return;
1956 return;
1957 end
1957 end
1958
1958
1959 sep=-1;
1959 sep=-1;
1960 i=0;
1960 i=0;
1961 j=0;
1961 j=0;
1962 l=0;
1962 l=0;
1963 nl=1;
1963 nl=1;
1964 while(i<nb)
1964 while(i<nb)
1965 #Get next character
1965 #Get next character
1966 c = s[i];
1966 c = s[i];
1967 if (c == "\n"[0])
1967 if (c == "\n"[0])
1968 #Explicit line break
1968 #Explicit line break
1969 Cell(w, h, s[j,i-j], 0, 2, '', fill, link);
1969 Cell(w, h, s[j,i-j], 0, 2, '', fill, link);
1970 i += 1;
1970 i += 1;
1971 sep = -1;
1971 sep = -1;
1972 j = i;
1972 j = i;
1973 l = 0;
1973 l = 0;
1974 if (nl == 1)
1974 if (nl == 1)
1975 @x = @l_margin;
1975 @x = @l_margin;
1976 w = @w - @r_margin - @x;
1976 w = @w - @r_margin - @x;
1977 wmax = (w - 2 * @c_margin);
1977 wmax = (w - 2 * @c_margin);
1978 end
1978 end
1979 nl += 1;
1979 nl += 1;
1980 next
1980 next
1981 end
1981 end
1982 if (c == " "[0])
1982 if (c == " "[0])
1983 sep= i;
1983 sep= i;
1984 end
1984 end
1985 l = GetStringWidth(s[j, i - j + 1]);
1985 l = GetStringWidth(s[j, i - j + 1]);
1986 if (l > wmax)
1986 if (l > wmax)
1987 #Automatic line break (word wrapping)
1987 #Automatic line break (word wrapping)
1988 if (sep == -1)
1988 if (sep == -1)
1989 if (@x > @l_margin)
1989 if (@x > @l_margin)
1990 #Move to next line
1990 #Move to next line
1991 @x = @l_margin;
1991 @x = @l_margin;
1992 @y += h;
1992 @y += h;
1993 w=@w - @r_margin - @x;
1993 w=@w - @r_margin - @x;
1994 wmax=(w - 2 * @c_margin);
1994 wmax=(w - 2 * @c_margin);
1995 i += 1
1995 i += 1
1996 nl += 1
1996 nl += 1
1997 next
1997 next
1998 end
1998 end
1999 if (i == j)
1999 if (i == j)
2000 i += 1
2000 i += 1
2001 end
2001 end
2002 Cell(w, h, s[j, (i-1)], 0, 2, '', fill, link);
2002 Cell(w, h, s[j, (i-1)], 0, 2, '', fill, link);
2003 else
2003 else
2004 Cell(w, h, s[j, (sep-j)], 0, 2, '', fill, link);
2004 Cell(w, h, s[j, (sep-j)], 0, 2, '', fill, link);
2005 i = sep+1;
2005 i = sep+1;
2006 end
2006 end
2007 sep = -1;
2007 sep = -1;
2008 j = i;
2008 j = i;
2009 l = 0;
2009 l = 0;
2010 if (nl==1)
2010 if (nl==1)
2011 @x = @l_margin;
2011 @x = @l_margin;
2012 w = @w - @r_margin - @x;
2012 w = @w - @r_margin - @x;
2013 wmax = (w - 2 * @c_margin);
2013 wmax = (w - 2 * @c_margin);
2014 end
2014 end
2015 nl += 1;
2015 nl += 1;
2016 else
2016 else
2017 i += 1;
2017 i += 1;
2018 end
2018 end
2019 end
2019 end
2020 #Last chunk
2020 #Last chunk
2021 if (i != j)
2021 if (i != j)
2022 Cell(GetStringWidth(s[j..i]), h, s[j..i], 0, 0, '', fill, link);
2022 Cell(GetStringWidth(s[j..i]), h, s[j..i], 0, 0, '', fill, link);
2023 end
2023 end
2024 end
2024 end
2025 alias_method :write, :Write
2025 alias_method :write, :Write
2026
2026
2027 #
2027 #
2028 # Puts an image in the page. The upper-left corner must be given. The dimensions can be specified in different ways:<ul><li>explicit width and height (expressed in user unit)</li><li>one explicit dimension, the other being calculated automatically in order to keep the original proportions</li><li>no explicit dimension, in which case the image is put at 72 dpi</li></ul>
2028 # Puts an image in the page. The upper-left corner must be given. The dimensions can be specified in different ways:<ul><li>explicit width and height (expressed in user unit)</li><li>one explicit dimension, the other being calculated automatically in order to keep the original proportions</li><li>no explicit dimension, in which case the image is put at 72 dpi</li></ul>
2029 # Supported formats are JPEG and PNG.
2029 # Supported formats are JPEG and PNG.
2030 # For JPEG, all flavors are allowed:<ul><li>gray scales</li><li>true colors (24 bits)</li><li>CMYK (32 bits)</li></ul>
2030 # For JPEG, all flavors are allowed:<ul><li>gray scales</li><li>true colors (24 bits)</li><li>CMYK (32 bits)</li></ul>
2031 # For PNG, are allowed:<ul><li>gray scales on at most 8 bits (256 levels)</li><li>indexed colors</li><li>true colors (24 bits)</li></ul>
2031 # For PNG, are allowed:<ul><li>gray scales on at most 8 bits (256 levels)</li><li>indexed colors</li><li>true colors (24 bits)</li></ul>
2032 # but are not supported:<ul><li>Interlacing</li><li>Alpha channel</li></ul>
2032 # but are not supported:<ul><li>Interlacing</li><li>Alpha channel</li></ul>
2033 # If a transparent color is defined, it will be taken into account (but will be only interpreted by Acrobat 4 and above).<br />
2033 # If a transparent color is defined, it will be taken into account (but will be only interpreted by Acrobat 4 and above).<br />
2034 # The format can be specified explicitly or inferred from the file extension.<br />
2034 # The format can be specified explicitly or inferred from the file extension.<br />
2035 # It is possible to put a link on the image.<br />
2035 # It is possible to put a link on the image.<br />
2036 # Remark: if an image is used several times, only one copy will be embedded in the file.<br />
2036 # Remark: if an image is used several times, only one copy will be embedded in the file.<br />
2037 # @param string :file Name of the file containing the image.
2037 # @param string :file Name of the file containing the image.
2038 # @param float :x Abscissa of the upper-left corner.
2038 # @param float :x Abscissa of the upper-left corner.
2039 # @param float :y Ordinate of the upper-left corner.
2039 # @param float :y Ordinate of the upper-left corner.
2040 # @param float :w Width of the image in the page. If not specified or equal to zero, it is automatically calculated.
2040 # @param float :w Width of the image in the page. If not specified or equal to zero, it is automatically calculated.
2041 # @param float :h Height of the image in the page. If not specified or equal to zero, it is automatically calculated.
2041 # @param float :h Height of the image in the page. If not specified or equal to zero, it is automatically calculated.
2042 # @param string :type Image format. Possible values are (case insensitive): JPG, JPEG, PNG. If not specified, the type is inferred from the file extension.
2042 # @param string :type Image format. Possible values are (case insensitive): JPG, JPEG, PNG. If not specified, the type is inferred from the file extension.
2043 # @param mixed :link URL or identifier returned by AddLink().
2043 # @param mixed :link URL or identifier returned by AddLink().
2044 # @since 1.1
2044 # @since 1.1
2045 # @see AddLink()
2045 # @see AddLink()
2046 #
2046 #
2047 def Image(file, x, y, w=0, h=0, type='', link=nil)
2047 def Image(file, x, y, w=0, h=0, type='', link=nil)
2048 #Put an image on the page
2048 #Put an image on the page
2049 if (@images[file].nil?)
2049 if (@images[file].nil?)
2050 #First use of image, get info
2050 #First use of image, get info
2051 if (type == '')
2051 if (type == '')
2052 pos = file.rindex('.');
2052 pos = File::basename(file).rindex('.');
2053 if (pos == 0)
2053 if (pos.nil? or pos == 0)
2054 Error('Image file has no extension and no type was specified: ' + file);
2054 Error('Image file has no extension and no type was specified: ' + file);
2055 end
2055 end
2056 pos = file.rindex('.');
2056 type = file[pos+1..-1];
2057 type = file[pos+1..-1];
2057 end
2058 end
2058 type.downcase!
2059 type.downcase!
2059 if (type == 'jpg' or type == 'jpeg')
2060 if (type == 'jpg' or type == 'jpeg')
2060 info=parsejpg(file);
2061 info=parsejpg(file);
2061 elsif (type == 'png')
2062 elsif (type == 'png' or type == 'gif')
2062 info=parsepng(file);
2063 img = Magick::ImageList.new(file)
2064 img.format = "PNG" # convert to PNG from gif
2065 img.opacity = 0 # PNG alpha channel delete
2066 File.open( @@k_path_cache + File::basename(file), 'w'){|f|
2067 f.binmode
2068 f.print img.to_blob
2069 f.close
2070 }
2071 info=parsepng( @@k_path_cache + File::basename(file));
2072 File.delete( @@k_path_cache + File::basename(file))
2063 else
2073 else
2064 #Allow for additional formats
2074 #Allow for additional formats
2065 mtd='parse' + type;
2075 mtd='parse' + type;
2066 if (!self.respond_to?(mtd))
2076 if (!self.respond_to?(mtd))
2067 Error('Unsupported image type: ' + type);
2077 Error('Unsupported image type: ' + type);
2068 end
2078 end
2069 info=send(mtd, file);
2079 info=send(mtd, file);
2070 end
2080 end
2071 info['i']=@images.length+1;
2081 info['i']=@images.length+1;
2072 @images[file] = info;
2082 @images[file] = info;
2073 else
2083 else
2074 info=@images[file];
2084 info=@images[file];
2075 end
2085 end
2076 #Automatic width and height calculation if needed
2086 #Automatic width and height calculation if needed
2077 if ((w == 0) and (h == 0))
2087 if ((w == 0) and (h == 0))
2088 rescale_x = (@w - @r_margin - x) / (info['w'] / (@img_scale * @k))
2089 rescale_x = 1 if rescale_x >= 1
2090 if (y + info['h'] * rescale_x / (@img_scale * @k) > @page_break_trigger and !@in_footer and AcceptPageBreak())
2091 #Automatic page break
2092 if @pages[@page+1].nil?
2093 ws = @ws;
2094 if (ws > 0)
2095 @ws = 0;
2096 out('0 Tw');
2097 end
2098 AddPage(@cur_orientation);
2099 if (ws > 0)
2100 @ws = ws;
2101 out(sprintf('%.3f Tw', ws * @k));
2102 end
2103 else
2104 @page += 1;
2105 end
2106 y=@t_margin;
2107 end
2108 rescale_y = (@page_break_trigger - y) / (info['h'] / (@img_scale * @k))
2109 rescale_y = 1 if rescale_y >= 1
2110 rescale = rescale_y >= rescale_x ? rescale_x : rescale_y
2111
2078 #Put image at 72 dpi
2112 #Put image at 72 dpi
2079 # 2004-06-14 :: Nicola Asuni, scale factor where added
2113 # 2004-06-14 :: Nicola Asuni, scale factor where added
2080 w = info['w'] / (@img_scale * @k);
2114 w = info['w'] * rescale / (@img_scale * @k);
2081 h = info['h'] / (@img_scale * @k);
2115 h = info['h'] * rescale / (@img_scale * @k);
2082 end
2116 elsif (w == 0)
2083 if (w == 0)
2084 w = h * info['w'] / info['h'];
2117 w = h * info['w'] / info['h'];
2085 end
2118 elsif (h == 0)
2086 if (h == 0)
2087 h = w * info['h'] / info['w'];
2119 h = w * info['h'] / info['w'];
2088 end
2120 end
2089 out(sprintf('q %.2f 0 0 %.2f %.2f %.2f cm /I%d Do Q', w*@k, h*@k, x*@k, (@h-(y+h))*@k, info['i']));
2121 out(sprintf('q %.2f 0 0 %.2f %.2f %.2f cm /I%d Do Q', w*@k, h*@k, x*@k, (@h-(y+h))*@k, info['i']));
2090 if (link)
2122 if (link)
2091 Link(x, y, w, h, link);
2123 Link(x, y, w, h, link);
2092 end
2124 end
2093
2125
2094 #2002-07-31 - Nicola Asuni
2126 #2002-07-31 - Nicola Asuni
2095 # set right-bottom corner coordinates
2127 # set right-bottom corner coordinates
2096 @img_rb_x = x + w;
2128 @img_rb_x = x + w;
2097 @img_rb_y = y + h;
2129 @img_rb_y = y + h;
2098 end
2130 end
2099 alias_method :image, :Image
2131 alias_method :image, :Image
2100
2132
2101 #
2133 #
2102 # Performs a line break. The current abscissa goes back to the left margin and the ordinate increases by the amount passed in parameter.
2134 # Performs a line break. The current abscissa goes back to the left margin and the ordinate increases by the amount passed in parameter.
2103 # @param float :h The height of the break. By default, the value equals the height of the last printed cell.
2135 # @param float :h The height of the break. By default, the value equals the height of the last printed cell.
2104 # @since 1.0
2136 # @since 1.0
2105 # @see Cell()
2137 # @see Cell()
2106 #
2138 #
2107 def Ln(h='')
2139 def Ln(h='')
2108 #Line feed; default value is last cell height
2140 #Line feed; default value is last cell height
2109 @x=@l_margin;
2141 @x=@l_margin;
2110 if (h.is_a?(String))
2142 if (h.is_a?(String))
2111 @y += @lasth;
2143 @y += @lasth;
2112 else
2144 else
2113 @y += h;
2145 @y += h;
2114 end
2146 end
2115
2147
2116 k=@k;
2148 k=@k;
2117 if (@y > @page_break_trigger and !@in_footer and AcceptPageBreak())
2149 if (@y > @page_break_trigger and !@in_footer and AcceptPageBreak())
2118 #Automatic page break
2150 #Automatic page break
2119 if @pages[@page+1].nil?
2151 if @pages[@page+1].nil?
2120 x = @x;
2152 x = @x;
2121 ws = @ws;
2153 ws = @ws;
2122 if (ws > 0)
2154 if (ws > 0)
2123 @ws = 0;
2155 @ws = 0;
2124 out('0 Tw');
2156 out('0 Tw');
2125 end
2157 end
2126 AddPage(@cur_orientation);
2158 AddPage(@cur_orientation);
2127 @x = x;
2159 @x = x;
2128 if (ws > 0)
2160 if (ws > 0)
2129 @ws = ws;
2161 @ws = ws;
2130 out(sprintf('%.3f Tw', ws * k));
2162 out(sprintf('%.3f Tw', ws * k));
2131 end
2163 end
2132 else
2164 else
2133 @page += 1;
2165 @page += 1;
2134 @y=@t_margin;
2166 @y=@t_margin;
2135 end
2167 end
2136 end
2168 end
2137
2169
2138 end
2170 end
2139 alias_method :ln, :Ln
2171 alias_method :ln, :Ln
2140
2172
2141 #
2173 #
2142 # Returns the abscissa of the current position.
2174 # Returns the abscissa of the current position.
2143 # @return float
2175 # @return float
2144 # @since 1.2
2176 # @since 1.2
2145 # @see SetX(), GetY(), SetY()
2177 # @see SetX(), GetY(), SetY()
2146 #
2178 #
2147 def GetX()
2179 def GetX()
2148 #Get x position
2180 #Get x position
2149 return @x;
2181 return @x;
2150 end
2182 end
2151 alias_method :get_x, :GetX
2183 alias_method :get_x, :GetX
2152
2184
2153 #
2185 #
2154 # Defines the abscissa of the current position. If the passed value is negative, it is relative to the right of the page.
2186 # Defines the abscissa of the current position. If the passed value is negative, it is relative to the right of the page.
2155 # @param float :x The value of the abscissa.
2187 # @param float :x The value of the abscissa.
2156 # @since 1.2
2188 # @since 1.2
2157 # @see GetX(), GetY(), SetY(), SetXY()
2189 # @see GetX(), GetY(), SetY(), SetXY()
2158 #
2190 #
2159 def SetX(x)
2191 def SetX(x)
2160 #Set x position
2192 #Set x position
2161 if (x>=0)
2193 if (x>=0)
2162 @x = x;
2194 @x = x;
2163 else
2195 else
2164 @x=@w+x;
2196 @x=@w+x;
2165 end
2197 end
2166 end
2198 end
2167 alias_method :set_x, :SetX
2199 alias_method :set_x, :SetX
2168
2200
2169 #
2201 #
2170 # Returns the ordinate of the current position.
2202 # Returns the ordinate of the current position.
2171 # @return float
2203 # @return float
2172 # @since 1.0
2204 # @since 1.0
2173 # @see SetY(), GetX(), SetX()
2205 # @see SetY(), GetX(), SetX()
2174 #
2206 #
2175 def GetY()
2207 def GetY()
2176 #Get y position
2208 #Get y position
2177 return @y;
2209 return @y;
2178 end
2210 end
2179 alias_method :get_y, :GetY
2211 alias_method :get_y, :GetY
2180
2212
2181 #
2213 #
2182 # Moves the current abscissa back to the left margin and sets the ordinate. If the passed value is negative, it is relative to the bottom of the page.
2214 # Moves the current abscissa back to the left margin and sets the ordinate. If the passed value is negative, it is relative to the bottom of the page.
2183 # @param float :y The value of the ordinate.
2215 # @param float :y The value of the ordinate.
2184 # @since 1.0
2216 # @since 1.0
2185 # @see GetX(), GetY(), SetY(), SetXY()
2217 # @see GetX(), GetY(), SetY(), SetXY()
2186 #
2218 #
2187 def SetY(y)
2219 def SetY(y)
2188 #Set y position and reset x
2220 #Set y position and reset x
2189 @x=@l_margin;
2221 @x=@l_margin;
2190 if (y>=0)
2222 if (y>=0)
2191 @y = y;
2223 @y = y;
2192 else
2224 else
2193 @y=@h+y;
2225 @y=@h+y;
2194 end
2226 end
2195 end
2227 end
2196 alias_method :set_y, :SetY
2228 alias_method :set_y, :SetY
2197
2229
2198 #
2230 #
2199 # Defines the abscissa and ordinate of the current position. If the passed values are negative, they are relative respectively to the right and bottom of the page.
2231 # Defines the abscissa and ordinate of the current position. If the passed values are negative, they are relative respectively to the right and bottom of the page.
2200 # @param float :x The value of the abscissa
2232 # @param float :x The value of the abscissa
2201 # @param float :y The value of the ordinate
2233 # @param float :y The value of the ordinate
2202 # @since 1.2
2234 # @since 1.2
2203 # @see SetX(), SetY()
2235 # @see SetX(), SetY()
2204 #
2236 #
2205 def SetXY(x, y)
2237 def SetXY(x, y)
2206 #Set x and y positions
2238 #Set x and y positions
2207 SetY(y);
2239 SetY(y);
2208 SetX(x);
2240 SetX(x);
2209 end
2241 end
2210 alias_method :set_xy, :SetXY
2242 alias_method :set_xy, :SetXY
2211
2243
2212 #
2244 #
2213 # Send the document to a given destination: string, local file or browser. In the last case, the plug-in may be used (if present) or a download ("Save as" dialog box) may be forced.<br />
2245 # Send the document to a given destination: string, local file or browser. In the last case, the plug-in may be used (if present) or a download ("Save as" dialog box) may be forced.<br />
2214 # The method first calls Close() if necessary to terminate the document.
2246 # The method first calls Close() if necessary to terminate the document.
2215 # @param string :name The name of the file. If not given, the document will be sent to the browser (destination I) with the name doc.pdf.
2247 # @param string :name The name of the file. If not given, the document will be sent to the browser (destination I) with the name doc.pdf.
2216 # @param string :dest Destination where to send the document. It can take one of the following values:<ul><li>I: send the file inline to the browser. The plug-in is used if available. The name given by name is used when one selects the "Save as" option on the link generating the PDF.</li><li>D: send to the browser and force a file download with the name given by name.</li><li>F: save to a local file with the name given by name.</li><li>S: return the document as a string. name is ignored.</li></ul>If the parameter is not specified but a name is given, destination is F. If no parameter is specified at all, destination is I.<br />
2248 # @param string :dest Destination where to send the document. It can take one of the following values:<ul><li>I: send the file inline to the browser. The plug-in is used if available. The name given by name is used when one selects the "Save as" option on the link generating the PDF.</li><li>D: send to the browser and force a file download with the name given by name.</li><li>F: save to a local file with the name given by name.</li><li>S: return the document as a string. name is ignored.</li></ul>If the parameter is not specified but a name is given, destination is F. If no parameter is specified at all, destination is I.<br />
2217 # @since 1.0
2249 # @since 1.0
2218 # @see Close()
2250 # @see Close()
2219 #
2251 #
2220 def Output(name='', dest='')
2252 def Output(name='', dest='')
2221 #Output PDF to some destination
2253 #Output PDF to some destination
2222 #Finish document if necessary
2254 #Finish document if necessary
2223 if (@state < 3)
2255 if (@state < 3)
2224 Close();
2256 Close();
2225 end
2257 end
2226 #Normalize parameters
2258 #Normalize parameters
2227 # Boolean no longer supported
2259 # Boolean no longer supported
2228 # if (dest.is_a?(Boolean))
2260 # if (dest.is_a?(Boolean))
2229 # dest = dest ? 'D' : 'F';
2261 # dest = dest ? 'D' : 'F';
2230 # end
2262 # end
2231 dest = dest.upcase
2263 dest = dest.upcase
2232 if (dest=='')
2264 if (dest=='')
2233 if (name=='')
2265 if (name=='')
2234 name='doc.pdf';
2266 name='doc.pdf';
2235 dest='I';
2267 dest='I';
2236 else
2268 else
2237 dest='F';
2269 dest='F';
2238 end
2270 end
2239 end
2271 end
2240 case (dest)
2272 case (dest)
2241 when 'I'
2273 when 'I'
2242 # This is PHP specific code
2274 # This is PHP specific code
2243 ##Send to standard output
2275 ##Send to standard output
2244 # if (ob_get_contents())
2276 # if (ob_get_contents())
2245 # Error('Some data has already been output, can\'t send PDF file');
2277 # Error('Some data has already been output, can\'t send PDF file');
2246 # end
2278 # end
2247 # if (php_sapi_name()!='cli')
2279 # if (php_sapi_name()!='cli')
2248 # #We send to a browser
2280 # #We send to a browser
2249 # header('Content-Type: application/pdf');
2281 # header('Content-Type: application/pdf');
2250 # if (headers_sent())
2282 # if (headers_sent())
2251 # Error('Some data has already been output to browser, can\'t send PDF file');
2283 # Error('Some data has already been output to browser, can\'t send PDF file');
2252 # end
2284 # end
2253 # header('Content-Length: ' + @buffer.length);
2285 # header('Content-Length: ' + @buffer.length);
2254 # header('Content-disposition: inline; filename="' + name + '"');
2286 # header('Content-disposition: inline; filename="' + name + '"');
2255 # end
2287 # end
2256 return @buffer;
2288 return @buffer;
2257
2289
2258 when 'D'
2290 when 'D'
2259 # PHP specific
2291 # PHP specific
2260 #Download file
2292 #Download file
2261 # if (ob_get_contents())
2293 # if (ob_get_contents())
2262 # Error('Some data has already been output, can\'t send PDF file');
2294 # Error('Some data has already been output, can\'t send PDF file');
2263 # end
2295 # end
2264 # if (!_SERVER['HTTP_USER_AGENT'].nil? && SERVER['HTTP_USER_AGENT'].include?('MSIE'))
2296 # if (!_SERVER['HTTP_USER_AGENT'].nil? && SERVER['HTTP_USER_AGENT'].include?('MSIE'))
2265 # header('Content-Type: application/force-download');
2297 # header('Content-Type: application/force-download');
2266 # else
2298 # else
2267 # header('Content-Type: application/octet-stream');
2299 # header('Content-Type: application/octet-stream');
2268 # end
2300 # end
2269 # if (headers_sent())
2301 # if (headers_sent())
2270 # Error('Some data has already been output to browser, can\'t send PDF file');
2302 # Error('Some data has already been output to browser, can\'t send PDF file');
2271 # end
2303 # end
2272 # header('Content-Length: '+ @buffer.length);
2304 # header('Content-Length: '+ @buffer.length);
2273 # header('Content-disposition: attachment; filename="' + name + '"');
2305 # header('Content-disposition: attachment; filename="' + name + '"');
2274 return @buffer;
2306 return @buffer;
2275
2307
2276 when 'F'
2308 when 'F'
2277 open(name,'wb') do |f|
2309 open(name,'wb') do |f|
2278 f.write(@buffer)
2310 f.write(@buffer)
2279 end
2311 end
2280 # PHP code
2312 # PHP code
2281 # #Save to local file
2313 # #Save to local file
2282 # f=open(name,'wb');
2314 # f=open(name,'wb');
2283 # if (!f)
2315 # if (!f)
2284 # Error('Unable to create output file: ' + name);
2316 # Error('Unable to create output file: ' + name);
2285 # end
2317 # end
2286 # fwrite(f,@buffer,@buffer.length);
2318 # fwrite(f,@buffer,@buffer.length);
2287 # f.close
2319 # f.close
2288
2320
2289 when 'S'
2321 when 'S'
2290 #Return as a string
2322 #Return as a string
2291 return @buffer;
2323 return @buffer;
2292 else
2324 else
2293 Error('Incorrect output destination: ' + dest);
2325 Error('Incorrect output destination: ' + dest);
2294
2326
2295 end
2327 end
2296 return '';
2328 return '';
2297 end
2329 end
2298 alias_method :output, :Output
2330 alias_method :output, :Output
2299
2331
2300 # Protected methods
2332 # Protected methods
2301
2333
2302 #
2334 #
2303 # Check for locale-related bug
2335 # Check for locale-related bug
2304 # @access protected
2336 # @access protected
2305 #
2337 #
2306 def dochecks()
2338 def dochecks()
2307 #Check for locale-related bug
2339 #Check for locale-related bug
2308 if (1.1==1)
2340 if (1.1==1)
2309 Error('Don\'t alter the locale before including class file');
2341 Error('Don\'t alter the locale before including class file');
2310 end
2342 end
2311 #Check for decimal separator
2343 #Check for decimal separator
2312 if (sprintf('%.1f',1.0)!='1.0')
2344 if (sprintf('%.1f',1.0)!='1.0')
2313 setlocale(LC_NUMERIC,'C');
2345 setlocale(LC_NUMERIC,'C');
2314 end
2346 end
2315 end
2347 end
2316
2348
2317 #
2349 #
2318 # Return fonts path
2350 # Return fonts path
2319 # @access protected
2351 # @access protected
2320 #
2352 #
2321 def getfontpath(file)
2353 def getfontpath(file)
2322 # Is it in the @@font_path?
2354 # Is it in the @@font_path?
2323 if @@font_path
2355 if @@font_path
2324 fpath = File.join @@font_path, file
2356 fpath = File.join @@font_path, file
2325 if File.exists?(fpath)
2357 if File.exists?(fpath)
2326 return fpath
2358 return fpath
2327 end
2359 end
2328 end
2360 end
2329 # Is it in this plugin's font folder?
2361 # Is it in this plugin's font folder?
2330 fpath = File.join File.dirname(__FILE__), 'fonts', file
2362 fpath = File.join File.dirname(__FILE__), 'fonts', file
2331 if File.exists?(fpath)
2363 if File.exists?(fpath)
2332 return fpath
2364 return fpath
2333 end
2365 end
2334 # Could not find it.
2366 # Could not find it.
2335 nil
2367 nil
2336 end
2368 end
2337
2369
2338 #
2370 #
2339 # Start document
2371 # Start document
2340 # @access protected
2372 # @access protected
2341 #
2373 #
2342 def begindoc()
2374 def begindoc()
2343 #Start document
2375 #Start document
2344 @state=1;
2376 @state=1;
2345 out('%PDF-1.3');
2377 out('%PDF-1.3');
2346 end
2378 end
2347
2379
2348 #
2380 #
2349 # putpages
2381 # putpages
2350 # @access protected
2382 # @access protected
2351 #
2383 #
2352 def putpages()
2384 def putpages()
2353 nb = @page;
2385 nb = @page;
2354 if (@alias_nb_pages)
2386 if (@alias_nb_pages)
2355 nbstr = UTF8ToUTF16BE(nb.to_s, false);
2387 nbstr = UTF8ToUTF16BE(nb.to_s, false);
2356 #Replace number of pages
2388 #Replace number of pages
2357 1.upto(nb) do |n|
2389 1.upto(nb) do |n|
2358 @pages[n].gsub!(@alias_nb_pages, nbstr)
2390 @pages[n].gsub!(@alias_nb_pages, nbstr)
2359 end
2391 end
2360 end
2392 end
2361 if @def_orientation=='P'
2393 if @def_orientation=='P'
2362 w_pt=@fw_pt
2394 w_pt=@fw_pt
2363 h_pt=@fh_pt
2395 h_pt=@fh_pt
2364 else
2396 else
2365 w_pt=@fh_pt
2397 w_pt=@fh_pt
2366 h_pt=@fw_pt
2398 h_pt=@fw_pt
2367 end
2399 end
2368 filter=(@compress) ? '/Filter /FlateDecode ' : ''
2400 filter=(@compress) ? '/Filter /FlateDecode ' : ''
2369 1.upto(nb) do |n|
2401 1.upto(nb) do |n|
2370 #Page
2402 #Page
2371 newobj
2403 newobj
2372 out('<</Type /Page')
2404 out('<</Type /Page')
2373 out('/Parent 1 0 R')
2405 out('/Parent 1 0 R')
2374 unless @orientation_changes[n].nil?
2406 unless @orientation_changes[n].nil?
2375 out(sprintf('/MediaBox [0 0 %.2f %.2f]', h_pt, w_pt))
2407 out(sprintf('/MediaBox [0 0 %.2f %.2f]', h_pt, w_pt))
2376 end
2408 end
2377 out('/Resources 2 0 R')
2409 out('/Resources 2 0 R')
2378 if @page_links[n]
2410 if @page_links[n]
2379 #Links
2411 #Links
2380 annots='/Annots ['
2412 annots='/Annots ['
2381 @page_links[n].each do |pl|
2413 @page_links[n].each do |pl|
2382 rect=sprintf('%.2f %.2f %.2f %.2f', pl[0], pl[1], pl[0]+pl[2], pl[1]-pl[3]);
2414 rect=sprintf('%.2f %.2f %.2f %.2f', pl[0], pl[1], pl[0]+pl[2], pl[1]-pl[3]);
2383 annots<<'<</Type /Annot /Subtype /Link /Rect [' + rect + '] /Border [0 0 0] ';
2415 annots<<'<</Type /Annot /Subtype /Link /Rect [' + rect + '] /Border [0 0 0] ';
2384 if (pl[4].is_a?(String))
2416 if (pl[4].is_a?(String))
2385 annots<<'/A <</S /URI /URI (' + escape(pl[4]) + ')>>>>';
2417 annots<<'/A <</S /URI /URI (' + escape(pl[4]) + ')>>>>';
2386 else
2418 else
2387 l=@links[pl[4]];
2419 l=@links[pl[4]];
2388 h=!@orientation_changes[l[0]].nil? ? w_pt : h_pt;
2420 h=!@orientation_changes[l[0]].nil? ? w_pt : h_pt;
2389 annots<<sprintf('/Dest [%d 0 R /XYZ 0 %.2f null]>>',1+2*l[0], h-l[1]*@k);
2421 annots<<sprintf('/Dest [%d 0 R /XYZ 0 %.2f null]>>',1+2*l[0], h-l[1]*@k);
2390 end
2422 end
2391 end
2423 end
2392 out(annots + ']');
2424 out(annots + ']');
2393 end
2425 end
2394 out('/Contents ' + (@n+1).to_s + ' 0 R>>');
2426 out('/Contents ' + (@n+1).to_s + ' 0 R>>');
2395 out('endobj');
2427 out('endobj');
2396 #Page content
2428 #Page content
2397 p=(@compress) ? gzcompress(@pages[n]) : @pages[n];
2429 p=(@compress) ? gzcompress(@pages[n]) : @pages[n];
2398 newobj();
2430 newobj();
2399 out('<<' + filter + '/Length '+ p.length.to_s + '>>');
2431 out('<<' + filter + '/Length '+ p.length.to_s + '>>');
2400 putstream(p);
2432 putstream(p);
2401 out('endobj');
2433 out('endobj');
2402 end
2434 end
2403 #Pages root
2435 #Pages root
2404 @offsets[1]=@buffer.length;
2436 @offsets[1]=@buffer.length;
2405 out('1 0 obj');
2437 out('1 0 obj');
2406 out('<</Type /Pages');
2438 out('<</Type /Pages');
2407 kids='/Kids [';
2439 kids='/Kids [';
2408 0.upto(nb) do |i|
2440 0.upto(nb) do |i|
2409 kids<<(3+2*i).to_s + ' 0 R ';
2441 kids<<(3+2*i).to_s + ' 0 R ';
2410 end
2442 end
2411 out(kids + ']');
2443 out(kids + ']');
2412 out('/Count ' + nb.to_s);
2444 out('/Count ' + nb.to_s);
2413 out(sprintf('/MediaBox [0 0 %.2f %.2f]', w_pt, h_pt));
2445 out(sprintf('/MediaBox [0 0 %.2f %.2f]', w_pt, h_pt));
2414 out('>>');
2446 out('>>');
2415 out('endobj');
2447 out('endobj');
2416 end
2448 end
2417
2449
2418 #
2450 #
2419 # Adds fonts
2451 # Adds fonts
2420 # putfonts
2452 # putfonts
2421 # @access protected
2453 # @access protected
2422 #
2454 #
2423 def putfonts()
2455 def putfonts()
2424 nf=@n;
2456 nf=@n;
2425 @diffs.each do |diff|
2457 @diffs.each do |diff|
2426 #Encodings
2458 #Encodings
2427 newobj();
2459 newobj();
2428 out('<</Type /Encoding /BaseEncoding /WinAnsiEncoding /Differences [' + diff + ']>>');
2460 out('<</Type /Encoding /BaseEncoding /WinAnsiEncoding /Differences [' + diff + ']>>');
2429 out('endobj');
2461 out('endobj');
2430 end
2462 end
2431 @font_files.each do |file, info|
2463 @font_files.each do |file, info|
2432 #Font file embedding
2464 #Font file embedding
2433 newobj();
2465 newobj();
2434 @font_files[file]['n']=@n;
2466 @font_files[file]['n']=@n;
2435 font='';
2467 font='';
2436 open(getfontpath(file),'rb') do |f|
2468 open(getfontpath(file),'rb') do |f|
2437 font = f.read();
2469 font = f.read();
2438 end
2470 end
2439 compressed=(file[-2,2]=='.z');
2471 compressed=(file[-2,2]=='.z');
2440 if (!compressed && !info['length2'].nil?)
2472 if (!compressed && !info['length2'].nil?)
2441 header=((font[0][0])==128);
2473 header=((font[0][0])==128);
2442 if (header)
2474 if (header)
2443 #Strip first binary header
2475 #Strip first binary header
2444 font=font[6];
2476 font=font[6];
2445 end
2477 end
2446 if header && (font[info['length1']][0] == 128)
2478 if header && (font[info['length1']][0] == 128)
2447 #Strip second binary header
2479 #Strip second binary header
2448 font=font[0..info['length1']] + font[info['length1']+6];
2480 font=font[0..info['length1']] + font[info['length1']+6];
2449 end
2481 end
2450 end
2482 end
2451 out('<</Length '+ font.length.to_s);
2483 out('<</Length '+ font.length.to_s);
2452 if (compressed)
2484 if (compressed)
2453 out('/Filter /FlateDecode');
2485 out('/Filter /FlateDecode');
2454 end
2486 end
2455 out('/Length1 ' + info['length1'].to_s);
2487 out('/Length1 ' + info['length1'].to_s);
2456 if (!info['length2'].nil?)
2488 if (!info['length2'].nil?)
2457 out('/Length2 ' + info['length2'].to_s + ' /Length3 0');
2489 out('/Length2 ' + info['length2'].to_s + ' /Length3 0');
2458 end
2490 end
2459 out('>>');
2491 out('>>');
2460 open(getfontpath(file),'rb') do |f|
2492 open(getfontpath(file),'rb') do |f|
2461 putstream(font)
2493 putstream(font)
2462 end
2494 end
2463 out('endobj');
2495 out('endobj');
2464 end
2496 end
2465 @fonts.each do |k, font|
2497 @fonts.each do |k, font|
2466 #Font objects
2498 #Font objects
2467 @fonts[k]['n']=@n+1;
2499 @fonts[k]['n']=@n+1;
2468 type = font['type'];
2500 type = font['type'];
2469 name = font['name'];
2501 name = font['name'];
2470 if (type=='core')
2502 if (type=='core')
2471 #Standard font
2503 #Standard font
2472 newobj();
2504 newobj();
2473 out('<</Type /Font');
2505 out('<</Type /Font');
2474 out('/BaseFont /' + name);
2506 out('/BaseFont /' + name);
2475 out('/Subtype /Type1');
2507 out('/Subtype /Type1');
2476 if (name!='Symbol' && name!='ZapfDingbats')
2508 if (name!='Symbol' && name!='ZapfDingbats')
2477 out('/Encoding /WinAnsiEncoding');
2509 out('/Encoding /WinAnsiEncoding');
2478 end
2510 end
2479 out('>>');
2511 out('>>');
2480 out('endobj');
2512 out('endobj');
2481 elsif type == 'Type0'
2513 elsif type == 'Type0'
2482 putType0(font)
2514 putType0(font)
2483 elsif (type=='Type1' || type=='TrueType')
2515 elsif (type=='Type1' || type=='TrueType')
2484 #Additional Type1 or TrueType font
2516 #Additional Type1 or TrueType font
2485 newobj();
2517 newobj();
2486 out('<</Type /Font');
2518 out('<</Type /Font');
2487 out('/BaseFont /' + name);
2519 out('/BaseFont /' + name);
2488 out('/Subtype /' + type);
2520 out('/Subtype /' + type);
2489 out('/FirstChar 32 /LastChar 255');
2521 out('/FirstChar 32 /LastChar 255');
2490 out('/Widths ' + (@n+1).to_s + ' 0 R');
2522 out('/Widths ' + (@n+1).to_s + ' 0 R');
2491 out('/FontDescriptor ' + (@n+2).to_s + ' 0 R');
2523 out('/FontDescriptor ' + (@n+2).to_s + ' 0 R');
2492 if (font['enc'])
2524 if (font['enc'])
2493 if (!font['diff'].nil?)
2525 if (!font['diff'].nil?)
2494 out('/Encoding ' + (nf+font['diff']).to_s + ' 0 R');
2526 out('/Encoding ' + (nf+font['diff']).to_s + ' 0 R');
2495 else
2527 else
2496 out('/Encoding /WinAnsiEncoding');
2528 out('/Encoding /WinAnsiEncoding');
2497 end
2529 end
2498 end
2530 end
2499 out('>>');
2531 out('>>');
2500 out('endobj');
2532 out('endobj');
2501 #Widths
2533 #Widths
2502 newobj();
2534 newobj();
2503 cw=font['cw']; # &
2535 cw=font['cw']; # &
2504 s='[';
2536 s='[';
2505 32.upto(255) do |i|
2537 32.upto(255) do |i|
2506 s << cw[i.chr] + ' ';
2538 s << cw[i.chr] + ' ';
2507 end
2539 end
2508 out(s + ']');
2540 out(s + ']');
2509 out('endobj');
2541 out('endobj');
2510 #Descriptor
2542 #Descriptor
2511 newobj();
2543 newobj();
2512 s='<</Type /FontDescriptor /FontName /' + name;
2544 s='<</Type /FontDescriptor /FontName /' + name;
2513 font['desc'].each do |k, v|
2545 font['desc'].each do |k, v|
2514 s<<' /' + k + ' ' + v;
2546 s<<' /' + k + ' ' + v;
2515 end
2547 end
2516 file = font['file'];
2548 file = font['file'];
2517 if (file)
2549 if (file)
2518 s<<' /FontFile' + (type=='Type1' ? '' : '2') + ' ' + @font_files[file]['n'] + ' 0 R';
2550 s<<' /FontFile' + (type=='Type1' ? '' : '2') + ' ' + @font_files[file]['n'] + ' 0 R';
2519 end
2551 end
2520 out(s + '>>');
2552 out(s + '>>');
2521 out('endobj');
2553 out('endobj');
2522 else
2554 else
2523 #Allow for additional types
2555 #Allow for additional types
2524 mtd='put' + type.downcase;
2556 mtd='put' + type.downcase;
2525 if (!self.respond_to?(mtd))
2557 if (!self.respond_to?(mtd))
2526 Error('Unsupported font type: ' + type)
2558 Error('Unsupported font type: ' + type)
2527 else
2559 else
2528 self.send(mtd,font)
2560 self.send(mtd,font)
2529 end
2561 end
2530 end
2562 end
2531 end
2563 end
2532 end
2564 end
2533
2565
2534 def putType0(font)
2566 def putType0(font)
2535 #Type0
2567 #Type0
2536 newobj();
2568 newobj();
2537 out('<</Type /Font')
2569 out('<</Type /Font')
2538 out('/Subtype /Type0')
2570 out('/Subtype /Type0')
2539 out('/BaseFont /'+font['name']+'-'+font['cMap'])
2571 out('/BaseFont /'+font['name']+'-'+font['cMap'])
2540 out('/Encoding /'+font['cMap'])
2572 out('/Encoding /'+font['cMap'])
2541 out('/DescendantFonts ['+(@n+1).to_s+' 0 R]')
2573 out('/DescendantFonts ['+(@n+1).to_s+' 0 R]')
2542 out('>>')
2574 out('>>')
2543 out('endobj')
2575 out('endobj')
2544 #CIDFont
2576 #CIDFont
2545 newobj()
2577 newobj()
2546 out('<</Type /Font')
2578 out('<</Type /Font')
2547 out('/Subtype /CIDFontType0')
2579 out('/Subtype /CIDFontType0')
2548 out('/BaseFont /'+font['name'])
2580 out('/BaseFont /'+font['name'])
2549 out('/CIDSystemInfo <</Registry (Adobe) /Ordering ('+font['registry']['ordering']+') /Supplement '+font['registry']['supplement'].to_s+'>>')
2581 out('/CIDSystemInfo <</Registry (Adobe) /Ordering ('+font['registry']['ordering']+') /Supplement '+font['registry']['supplement'].to_s+'>>')
2550 out('/FontDescriptor '+(@n+1).to_s+' 0 R')
2582 out('/FontDescriptor '+(@n+1).to_s+' 0 R')
2551 w='/W [1 ['
2583 w='/W [1 ['
2552 font['cw'].keys.sort.each {|key|
2584 font['cw'].keys.sort.each {|key|
2553 w+=font['cw'][key].to_s + " "
2585 w+=font['cw'][key].to_s + " "
2554 # ActionController::Base::logger.debug key.to_s
2586 # ActionController::Base::logger.debug key.to_s
2555 # ActionController::Base::logger.debug font['cw'][key].to_s
2587 # ActionController::Base::logger.debug font['cw'][key].to_s
2556 }
2588 }
2557 out(w+'] 231 325 500 631 [500] 326 389 500]')
2589 out(w+'] 231 325 500 631 [500] 326 389 500]')
2558 out('>>')
2590 out('>>')
2559 out('endobj')
2591 out('endobj')
2560 #Font descriptor
2592 #Font descriptor
2561 newobj()
2593 newobj()
2562 out('<</Type /FontDescriptor')
2594 out('<</Type /FontDescriptor')
2563 out('/FontName /'+font['name'])
2595 out('/FontName /'+font['name'])
2564 out('/Flags 6')
2596 out('/Flags 6')
2565 out('/FontBBox [0 -200 1000 900]')
2597 out('/FontBBox [0 -200 1000 900]')
2566 out('/ItalicAngle 0')
2598 out('/ItalicAngle 0')
2567 out('/Ascent 800')
2599 out('/Ascent 800')
2568 out('/Descent -200')
2600 out('/Descent -200')
2569 out('/CapHeight 800')
2601 out('/CapHeight 800')
2570 out('/StemV 60')
2602 out('/StemV 60')
2571 out('>>')
2603 out('>>')
2572 out('endobj')
2604 out('endobj')
2573 end
2605 end
2574
2606
2575 #
2607 #
2576 # putimages
2608 # putimages
2577 # @access protected
2609 # @access protected
2578 #
2610 #
2579 def putimages()
2611 def putimages()
2580 filter=(@compress) ? '/Filter /FlateDecode ' : '';
2612 filter=(@compress) ? '/Filter /FlateDecode ' : '';
2581 @images.each do |file, info| # was while(list(file, info)=each(@images))
2613 @images.each do |file, info| # was while(list(file, info)=each(@images))
2582 newobj();
2614 newobj();
2583 @images[file]['n']=@n;
2615 @images[file]['n']=@n;
2584 out('<</Type /XObject');
2616 out('<</Type /XObject');
2585 out('/Subtype /Image');
2617 out('/Subtype /Image');
2586 out('/Width ' + info['w'].to_s);
2618 out('/Width ' + info['w'].to_s);
2587 out('/Height ' + info['h'].to_s);
2619 out('/Height ' + info['h'].to_s);
2588 if (info['cs']=='Indexed')
2620 if (info['cs']=='Indexed')
2589 out('/ColorSpace [/Indexed /DeviceRGB ' + (info['pal'].length/3-1).to_s + ' ' + (@n+1).to_s + ' 0 R]');
2621 out('/ColorSpace [/Indexed /DeviceRGB ' + (info['pal'].length/3-1).to_s + ' ' + (@n+1).to_s + ' 0 R]');
2590 else
2622 else
2591 out('/ColorSpace /' + info['cs']);
2623 out('/ColorSpace /' + info['cs']);
2592 if (info['cs']=='DeviceCMYK')
2624 if (info['cs']=='DeviceCMYK')
2593 out('/Decode [1 0 1 0 1 0 1 0]');
2625 out('/Decode [1 0 1 0 1 0 1 0]');
2594 end
2626 end
2595 end
2627 end
2596 out('/BitsPerComponent ' + info['bpc'].to_s);
2628 out('/BitsPerComponent ' + info['bpc'].to_s);
2597 if (!info['f'].nil?)
2629 if (!info['f'].nil?)
2598 out('/Filter /' + info['f']);
2630 out('/Filter /' + info['f']);
2599 end
2631 end
2600 if (!info['parms'].nil?)
2632 if (!info['parms'].nil?)
2601 out(info['parms']);
2633 out(info['parms']);
2602 end
2634 end
2603 if (!info['trns'].nil? and info['trns'].kind_of?(Array))
2635 if (!info['trns'].nil? and info['trns'].kind_of?(Array))
2604 trns='';
2636 trns='';
2605 0.upto(info['trns'].length) do |i|
2637 0.upto(info['trns'].length) do |i|
2606 trns << info['trns'][i] + ' ' + info['trns'][i] + ' ';
2638 trns << info['trns'][i] + ' ' + info['trns'][i] + ' ';
2607 end
2639 end
2608 out('/Mask [' + trns + ']');
2640 out('/Mask [' + trns + ']');
2609 end
2641 end
2610 out('/Length ' + info['data'].length.to_s + '>>');
2642 out('/Length ' + info['data'].length.to_s + '>>');
2611 putstream(info['data']);
2643 putstream(info['data']);
2612 @images[file]['data']=nil
2644 @images[file]['data']=nil
2613 out('endobj');
2645 out('endobj');
2614 #Palette
2646 #Palette
2615 if (info['cs']=='Indexed')
2647 if (info['cs']=='Indexed')
2616 newobj();
2648 newobj();
2617 pal=(@compress) ? gzcompress(info['pal']) : info['pal'];
2649 pal=(@compress) ? gzcompress(info['pal']) : info['pal'];
2618 out('<<' + filter + '/Length ' + pal.length.to_s + '>>');
2650 out('<<' + filter + '/Length ' + pal.length.to_s + '>>');
2619 putstream(pal);
2651 putstream(pal);
2620 out('endobj');
2652 out('endobj');
2621 end
2653 end
2622 end
2654 end
2623 end
2655 end
2624
2656
2625 #
2657 #
2626 # putxobjectdict
2658 # putxobjectdict
2627 # @access protected
2659 # @access protected
2628 #
2660 #
2629 def putxobjectdict()
2661 def putxobjectdict()
2630 @images.each_value do |image|
2662 @images.each_value do |image|
2631 out('/I' + image['i'].to_s + ' ' + image['n'].to_s + ' 0 R');
2663 out('/I' + image['i'].to_s + ' ' + image['n'].to_s + ' 0 R');
2632 end
2664 end
2633 end
2665 end
2634
2666
2635 #
2667 #
2636 # putresourcedict
2668 # putresourcedict
2637 # @access protected
2669 # @access protected
2638 #
2670 #
2639 def putresourcedict()
2671 def putresourcedict()
2640 out('/ProcSet [/PDF /Text /ImageB /ImageC /ImageI]');
2672 out('/ProcSet [/PDF /Text /ImageB /ImageC /ImageI]');
2641 out('/Font <<');
2673 out('/Font <<');
2642 @fonts.each_value do |font|
2674 @fonts.each_value do |font|
2643 out('/F' + font['i'].to_s + ' ' + font['n'].to_s + ' 0 R');
2675 out('/F' + font['i'].to_s + ' ' + font['n'].to_s + ' 0 R');
2644 end
2676 end
2645 out('>>');
2677 out('>>');
2646 out('/XObject <<');
2678 out('/XObject <<');
2647 putxobjectdict();
2679 putxobjectdict();
2648 out('>>');
2680 out('>>');
2649 end
2681 end
2650
2682
2651 #
2683 #
2652 # putresources
2684 # putresources
2653 # @access protected
2685 # @access protected
2654 #
2686 #
2655 def putresources()
2687 def putresources()
2656 putfonts();
2688 putfonts();
2657 putimages();
2689 putimages();
2658 #Resource dictionary
2690 #Resource dictionary
2659 @offsets[2]=@buffer.length;
2691 @offsets[2]=@buffer.length;
2660 out('2 0 obj');
2692 out('2 0 obj');
2661 out('<<');
2693 out('<<');
2662 putresourcedict();
2694 putresourcedict();
2663 out('>>');
2695 out('>>');
2664 out('endobj');
2696 out('endobj');
2665 end
2697 end
2666
2698
2667 #
2699 #
2668 # putinfo
2700 # putinfo
2669 # @access protected
2701 # @access protected
2670 #
2702 #
2671 def putinfo()
2703 def putinfo()
2672 out('/Producer ' + textstring(PDF_PRODUCER));
2704 out('/Producer ' + textstring(PDF_PRODUCER));
2673 if (!@title.nil?)
2705 if (!@title.nil?)
2674 out('/Title ' + textstring(@title));
2706 out('/Title ' + textstring(@title));
2675 end
2707 end
2676 if (!@subject.nil?)
2708 if (!@subject.nil?)
2677 out('/Subject ' + textstring(@subject));
2709 out('/Subject ' + textstring(@subject));
2678 end
2710 end
2679 if (!@author.nil?)
2711 if (!@author.nil?)
2680 out('/Author ' + textstring(@author));
2712 out('/Author ' + textstring(@author));
2681 end
2713 end
2682 if (!@keywords.nil?)
2714 if (!@keywords.nil?)
2683 out('/Keywords ' + textstring(@keywords));
2715 out('/Keywords ' + textstring(@keywords));
2684 end
2716 end
2685 if (!@creator.nil?)
2717 if (!@creator.nil?)
2686 out('/Creator ' + textstring(@creator));
2718 out('/Creator ' + textstring(@creator));
2687 end
2719 end
2688 out('/CreationDate ' + textstring('D:' + Time.now.strftime('%Y%m%d%H%M%S')));
2720 out('/CreationDate ' + textstring('D:' + Time.now.strftime('%Y%m%d%H%M%S')));
2689 end
2721 end
2690
2722
2691 #
2723 #
2692 # putcatalog
2724 # putcatalog
2693 # @access protected
2725 # @access protected
2694 #
2726 #
2695 def putcatalog()
2727 def putcatalog()
2696 out('/Type /Catalog');
2728 out('/Type /Catalog');
2697 out('/Pages 1 0 R');
2729 out('/Pages 1 0 R');
2698 if (@zoom_mode=='fullpage')
2730 if (@zoom_mode=='fullpage')
2699 out('/OpenAction [3 0 R /Fit]');
2731 out('/OpenAction [3 0 R /Fit]');
2700 elsif (@zoom_mode=='fullwidth')
2732 elsif (@zoom_mode=='fullwidth')
2701 out('/OpenAction [3 0 R /FitH null]');
2733 out('/OpenAction [3 0 R /FitH null]');
2702 elsif (@zoom_mode=='real')
2734 elsif (@zoom_mode=='real')
2703 out('/OpenAction [3 0 R /XYZ null null 1]');
2735 out('/OpenAction [3 0 R /XYZ null null 1]');
2704 elsif (!@zoom_mode.is_a?(String))
2736 elsif (!@zoom_mode.is_a?(String))
2705 out('/OpenAction [3 0 R /XYZ null null ' + (@zoom_mode/100) + ']');
2737 out('/OpenAction [3 0 R /XYZ null null ' + (@zoom_mode/100) + ']');
2706 end
2738 end
2707 if (@layout_mode=='single')
2739 if (@layout_mode=='single')
2708 out('/PageLayout /SinglePage');
2740 out('/PageLayout /SinglePage');
2709 elsif (@layout_mode=='continuous')
2741 elsif (@layout_mode=='continuous')
2710 out('/PageLayout /OneColumn');
2742 out('/PageLayout /OneColumn');
2711 elsif (@layout_mode=='two')
2743 elsif (@layout_mode=='two')
2712 out('/PageLayout /TwoColumnLeft');
2744 out('/PageLayout /TwoColumnLeft');
2713 end
2745 end
2714 end
2746 end
2715
2747
2716 #
2748 #
2717 # puttrailer
2749 # puttrailer
2718 # @access protected
2750 # @access protected
2719 #
2751 #
2720 def puttrailer()
2752 def puttrailer()
2721 out('/Size ' + (@n+1).to_s);
2753 out('/Size ' + (@n+1).to_s);
2722 out('/Root ' + @n.to_s + ' 0 R');
2754 out('/Root ' + @n.to_s + ' 0 R');
2723 out('/Info ' + (@n-1).to_s + ' 0 R');
2755 out('/Info ' + (@n-1).to_s + ' 0 R');
2724 end
2756 end
2725
2757
2726 #
2758 #
2727 # putheader
2759 # putheader
2728 # @access protected
2760 # @access protected
2729 #
2761 #
2730 def putheader()
2762 def putheader()
2731 out('%PDF-' + @pdf_version);
2763 out('%PDF-' + @pdf_version);
2732 end
2764 end
2733
2765
2734 #
2766 #
2735 # enddoc
2767 # enddoc
2736 # @access protected
2768 # @access protected
2737 #
2769 #
2738 def enddoc()
2770 def enddoc()
2739 putheader();
2771 putheader();
2740 putpages();
2772 putpages();
2741 putresources();
2773 putresources();
2742 #Info
2774 #Info
2743 newobj();
2775 newobj();
2744 out('<<');
2776 out('<<');
2745 putinfo();
2777 putinfo();
2746 out('>>');
2778 out('>>');
2747 out('endobj');
2779 out('endobj');
2748 #Catalog
2780 #Catalog
2749 newobj();
2781 newobj();
2750 out('<<');
2782 out('<<');
2751 putcatalog();
2783 putcatalog();
2752 out('>>');
2784 out('>>');
2753 out('endobj');
2785 out('endobj');
2754 #Cross-ref
2786 #Cross-ref
2755 o=@buffer.length;
2787 o=@buffer.length;
2756 out('xref');
2788 out('xref');
2757 out('0 ' + (@n+1).to_s);
2789 out('0 ' + (@n+1).to_s);
2758 out('0000000000 65535 f ');
2790 out('0000000000 65535 f ');
2759 1.upto(@n) do |i|
2791 1.upto(@n) do |i|
2760 out(sprintf('%010d 00000 n ',@offsets[i]));
2792 out(sprintf('%010d 00000 n ',@offsets[i]));
2761 end
2793 end
2762 #Trailer
2794 #Trailer
2763 out('trailer');
2795 out('trailer');
2764 out('<<');
2796 out('<<');
2765 puttrailer();
2797 puttrailer();
2766 out('>>');
2798 out('>>');
2767 out('startxref');
2799 out('startxref');
2768 out(o);
2800 out(o);
2769 out('%%EOF');
2801 out('%%EOF');
2770 @state=3;
2802 @state=3;
2771 end
2803 end
2772
2804
2773 #
2805 #
2774 # beginpage
2806 # beginpage
2775 # @access protected
2807 # @access protected
2776 #
2808 #
2777 def beginpage(orientation)
2809 def beginpage(orientation)
2778 @page += 1;
2810 @page += 1;
2779 @pages[@page]='';
2811 @pages[@page]='';
2780 @state=2;
2812 @state=2;
2781 @x=@l_margin;
2813 @x=@l_margin;
2782 @y=@t_margin;
2814 @y=@t_margin;
2783 @font_family='';
2815 @font_family='';
2784 #Page orientation
2816 #Page orientation
2785 if (orientation.empty?)
2817 if (orientation.empty?)
2786 orientation=@def_orientation;
2818 orientation=@def_orientation;
2787 else
2819 else
2788 orientation.upcase!
2820 orientation.upcase!
2789 if (orientation!=@def_orientation)
2821 if (orientation!=@def_orientation)
2790 @orientation_changes[@page]=true;
2822 @orientation_changes[@page]=true;
2791 end
2823 end
2792 end
2824 end
2793 if (orientation!=@cur_orientation)
2825 if (orientation!=@cur_orientation)
2794 #Change orientation
2826 #Change orientation
2795 if (orientation=='P')
2827 if (orientation=='P')
2796 @w_pt=@fw_pt;
2828 @w_pt=@fw_pt;
2797 @h_pt=@fh_pt;
2829 @h_pt=@fh_pt;
2798 @w=@fw;
2830 @w=@fw;
2799 @h=@fh;
2831 @h=@fh;
2800 else
2832 else
2801 @w_pt=@fh_pt;
2833 @w_pt=@fh_pt;
2802 @h_pt=@fw_pt;
2834 @h_pt=@fw_pt;
2803 @w=@fh;
2835 @w=@fh;
2804 @h=@fw;
2836 @h=@fw;
2805 end
2837 end
2806 @page_break_trigger=@h-@b_margin;
2838 @page_break_trigger=@h-@b_margin;
2807 @cur_orientation = orientation;
2839 @cur_orientation = orientation;
2808 end
2840 end
2809 end
2841 end
2810
2842
2811 #
2843 #
2812 # End of page contents
2844 # End of page contents
2813 # @access protected
2845 # @access protected
2814 #
2846 #
2815 def endpage()
2847 def endpage()
2816 @state=1;
2848 @state=1;
2817 end
2849 end
2818
2850
2819 #
2851 #
2820 # Begin a new object
2852 # Begin a new object
2821 # @access protected
2853 # @access protected
2822 #
2854 #
2823 def newobj()
2855 def newobj()
2824 @n += 1;
2856 @n += 1;
2825 @offsets[@n]=@buffer.length;
2857 @offsets[@n]=@buffer.length;
2826 out(@n.to_s + ' 0 obj');
2858 out(@n.to_s + ' 0 obj');
2827 end
2859 end
2828
2860
2829 #
2861 #
2830 # Underline and Deleted text
2862 # Underline and Deleted text
2831 # @access protected
2863 # @access protected
2832 #
2864 #
2833 def dolinetxt(x, y, txt)
2865 def dolinetxt(x, y, txt)
2834 up = @current_font['up'];
2866 up = @current_font['up'];
2835 ut = @current_font['ut'];
2867 ut = @current_font['ut'];
2836 w = GetStringWidth(txt) + @ws * txt.count(' ');
2868 w = GetStringWidth(txt) + @ws * txt.count(' ');
2837 sprintf('%.2f %.2f %.2f %.2f re f', x * @k, (@h - (y - up / 1000.0 * @font_size)) * @k, w * @k, -ut / 1000.0 * @font_size_pt);
2869 sprintf('%.2f %.2f %.2f %.2f re f', x * @k, (@h - (y - up / 1000.0 * @font_size)) * @k, w * @k, -ut / 1000.0 * @font_size_pt);
2838 end
2870 end
2839
2871
2840 #
2872 #
2841 # Extract info from a JPEG file
2873 # Extract info from a JPEG file
2842 # @access protected
2874 # @access protected
2843 #
2875 #
2844 def parsejpg(file)
2876 def parsejpg(file)
2845 a=getimagesize(file);
2877 a=getimagesize(file);
2846 if (a.empty?)
2878 if (a.empty?)
2847 Error('Missing or incorrect image file: ' + file);
2879 Error('Missing or incorrect image file: ' + file);
2848 end
2880 end
2849 if (a[2]!='JPEG')
2881 if (!a[2].nil? and a[2]!='JPEG')
2850 Error('Not a JPEG file: ' + file);
2882 Error('Not a JPEG file: ' + file);
2851 end
2883 end
2852 if (a['channels'].nil? or a['channels']==3)
2884 if (a['channels'].nil? or a['channels']==3)
2853 colspace='DeviceRGB';
2885 colspace='DeviceRGB';
2854 elsif (a['channels']==4)
2886 elsif (a['channels']==4)
2855 colspace='DeviceCMYK';
2887 colspace='DeviceCMYK';
2856 else
2888 else
2857 colspace='DeviceGray';
2889 colspace='DeviceGray';
2858 end
2890 end
2859 bpc=!a['bits'].nil? ? a['bits'] : 8;
2891 bpc=!a['bits'].nil? ? a['bits'] : 8;
2860 #Read whole file
2892 #Read whole file
2861 data='';
2893 data='';
2862 open(file,'rb') do |f|
2894
2895 open( @@k_path_cache + File::basename(file),'rb') do |f|
2863 data<<f.read();
2896 data<<f.read();
2864 end
2897 end
2898 File.delete( @@k_path_cache + File::basename(file))
2899
2865 return {'w' => a[0],'h' => a[1],'cs' => colspace,'bpc' => bpc,'f'=>'DCTDecode','data' => data}
2900 return {'w' => a[0],'h' => a[1],'cs' => colspace,'bpc' => bpc,'f'=>'DCTDecode','data' => data}
2866 end
2901 end
2867
2902
2868 #
2903 #
2869 # Extract info from a PNG file
2904 # Extract info from a PNG file
2870 # @access protected
2905 # @access protected
2871 #
2906 #
2872 def parsepng(file)
2907 def parsepng(file)
2873 f=open(file,'rb');
2908 f=open(file,'rb');
2874 #Check signature
2909 #Check signature
2875 if (f.read(8)!=137.chr + 'PNG' + 13.chr + 10.chr + 26.chr + 10.chr)
2910 if (f.read(8)!=137.chr + 'PNG' + 13.chr + 10.chr + 26.chr + 10.chr)
2876 Error('Not a PNG file: ' + file);
2911 Error('Not a PNG file: ' + file);
2877 end
2912 end
2878 #Read header chunk
2913 #Read header chunk
2879 f.read(4);
2914 f.read(4);
2880 if (f.read(4)!='IHDR')
2915 if (f.read(4)!='IHDR')
2881 Error('Incorrect PNG file: ' + file);
2916 Error('Incorrect PNG file: ' + file);
2882 end
2917 end
2883 w=freadint(f);
2918 w=freadint(f);
2884 h=freadint(f);
2919 h=freadint(f);
2885 bpc=f.read(1)[0];
2920 bpc=f.read(1).unpack('C')[0];
2886 if (bpc>8)
2921 if (bpc>8)
2887 Error('16-bit depth not supported: ' + file);
2922 Error('16-bit depth not supported: ' + file);
2888 end
2923 end
2889 ct=f.read(1)[0];
2924 ct=f.read(1).unpack('C')[0];
2890 if (ct==0)
2925 if (ct==0)
2891 colspace='DeviceGray';
2926 colspace='DeviceGray';
2892 elsif (ct==2)
2927 elsif (ct==2)
2893 colspace='DeviceRGB';
2928 colspace='DeviceRGB';
2894 elsif (ct==3)
2929 elsif (ct==3)
2895 colspace='Indexed';
2930 colspace='Indexed';
2896 else
2931 else
2897 Error('Alpha channel not supported: ' + file);
2932 Error('Alpha channel not supported: ' + file);
2898 end
2933 end
2899 if (f.read(1)[0] != 0)
2934 if (f.read(1).unpack('C')[0] != 0)
2900 Error('Unknown compression method: ' + file);
2935 Error('Unknown compression method: ' + file);
2901 end
2936 end
2902 if (f.read(1)[0]!=0)
2937 if (f.read(1).unpack('C')[0] != 0)
2903 Error('Unknown filter method: ' + file);
2938 Error('Unknown filter method: ' + file);
2904 end
2939 end
2905 if (f.read(1)[0]!=0)
2940 if (f.read(1).unpack('C')[0] != 0)
2906 Error('Interlacing not supported: ' + file);
2941 Error('Interlacing not supported: ' + file);
2907 end
2942 end
2908 f.read(4);
2943 f.read(4);
2909 parms='/DecodeParms <</Predictor 15 /Colors ' + (ct==2 ? 3 : 1).to_s + ' /BitsPerComponent ' + bpc.to_s + ' /Columns ' + w.to_s + '>>';
2944 parms='/DecodeParms <</Predictor 15 /Colors ' + (ct==2 ? 3 : 1).to_s + ' /BitsPerComponent ' + bpc.to_s + ' /Columns ' + w.to_s + '>>';
2910 #Scan chunks looking for palette, transparency and image data
2945 #Scan chunks looking for palette, transparency and image data
2911 pal='';
2946 pal='';
2912 trns='';
2947 trns='';
2913 data='';
2948 data='';
2914 begin
2949 begin
2915 n=freadint(f);
2950 n=freadint(f);
2916 type=f.read(4);
2951 type=f.read(4);
2917 if (type=='PLTE')
2952 if (type=='PLTE')
2918 #Read palette
2953 #Read palette
2919 pal=f.read( n);
2954 pal=f.read( n);
2920 f.read(4);
2955 f.read(4);
2921 elsif (type=='tRNS')
2956 elsif (type=='tRNS')
2922 #Read transparency info
2957 #Read transparency info
2923 t=f.read( n);
2958 t=f.read( n);
2924 if (ct==0)
2959 if (ct==0)
2925 trns = t[1][0]
2960 trns = t[1].unpack('C')[0]
2926 elsif (ct==2)
2961 elsif (ct==2)
2927 trns = t[[1][0], t[3][0], t[5][0]]
2962 trns = t[[1].unpack('C')[0], t[3].unpack('C')[0], t[5].unpack('C')[0]]
2928 else
2963 else
2929 pos=t.include?(0.chr);
2964 pos=t.include?(0.chr);
2930 if (pos!=false)
2965 if (pos!=false)
2931 trns = [pos]
2966 trns = [pos]
2932 end
2967 end
2933 end
2968 end
2934 f.read(4);
2969 f.read(4);
2935 elsif (type=='IDAT')
2970 elsif (type=='IDAT')
2936 #Read image data block
2971 #Read image data block
2937 data<<f.read( n);
2972 data<<f.read( n);
2938 f.read(4);
2973 f.read(4);
2939 elsif (type=='IEND')
2974 elsif (type=='IEND')
2940 break;
2975 break;
2941 else
2976 else
2942 f.read( n+4);
2977 f.read( n+4);
2943 end
2978 end
2944 end while(n)
2979 end while(n)
2945 if (colspace=='Indexed' and pal.empty?)
2980 if (colspace=='Indexed' and pal.empty?)
2946 Error('Missing palette in ' + file);
2981 Error('Missing palette in ' + file);
2947 end
2982 end
2948 f.close
2983 f.close
2949 return {'w' => w, 'h' => h, 'cs' => colspace, 'bpc' => bpc, 'f'=>'FlateDecode', 'parms' => parms, 'pal' => pal, 'trns' => trns, 'data' => data}
2984 return {'w' => w, 'h' => h, 'cs' => colspace, 'bpc' => bpc, 'f'=>'FlateDecode', 'parms' => parms, 'pal' => pal, 'trns' => trns, 'data' => data}
2950 end
2985 end
2951
2986
2952 #
2987 #
2953 # Read a 4-byte integer from file
2988 # Read a 4-byte integer from file
2954 # @access protected
2989 # @access protected
2955 #
2990 #
2956 def freadint(f)
2991 def freadint(f)
2957 # Read a 4-byte integer from file
2992 # Read a 4-byte integer from file
2958 a = f.read(4).unpack('N')
2993 a = f.read(4).unpack('N')
2959 return a[0]
2994 return a[0]
2960 end
2995 end
2961
2996
2962 #
2997 #
2963 # Format a text string
2998 # Format a text string
2964 # @access protected
2999 # @access protected
2965 #
3000 #
2966 def textstring(s)
3001 def textstring(s)
2967 if (@is_unicode)
3002 if (@is_unicode)
2968 #Convert string to UTF-16BE
3003 #Convert string to UTF-16BE
2969 s = UTF8ToUTF16BE(s, true);
3004 s = UTF8ToUTF16BE(s, true);
2970 end
3005 end
2971 return '(' + escape(s) + ')';
3006 return '(' + escape(s) + ')';
2972 end
3007 end
2973
3008
2974 #
3009 #
2975 # Format a text string
3010 # Format a text string
2976 # @access protected
3011 # @access protected
2977 #
3012 #
2978 def escapetext(s)
3013 def escapetext(s)
2979 if (@is_unicode)
3014 if (@is_unicode)
2980 #Convert string to UTF-16BE
3015 #Convert string to UTF-16BE
2981 s = UTF8ToUTF16BE(s, false);
3016 s = UTF8ToUTF16BE(s, false);
2982 end
3017 end
2983 return escape(s);
3018 return escape(s);
2984 end
3019 end
2985
3020
2986 #
3021 #
2987 # Add \ before \, ( and )
3022 # Add \ before \, ( and )
2988 # @access protected
3023 # @access protected
2989 #
3024 #
2990 def escape(s)
3025 def escape(s)
2991 # Add \ before \, ( and )
3026 # Add \ before \, ( and )
2992 s.gsub('\\','\\\\\\').gsub('(','\\(').gsub(')','\\)').gsub(13.chr, '\r')
3027 s.gsub('\\','\\\\\\').gsub('(','\\(').gsub(')','\\)').gsub(13.chr, '\r')
2993 end
3028 end
2994
3029
2995 #
3030 #
2996 #
3031 #
2997 # @access protected
3032 # @access protected
2998 #
3033 #
2999 def putstream(s)
3034 def putstream(s)
3000 out('stream');
3035 out('stream');
3001 out(s);
3036 out(s);
3002 out('endstream');
3037 out('endstream');
3003 end
3038 end
3004
3039
3005 #
3040 #
3006 # Add a line to the document
3041 # Add a line to the document
3007 # @access protected
3042 # @access protected
3008 #
3043 #
3009 def out(s)
3044 def out(s)
3010 if (@state==2)
3045 if (@state==2)
3011 @pages[@page] << s.to_s + "\n";
3046 @pages[@page] << s.to_s + "\n";
3012 else
3047 else
3013 @buffer << s.to_s + "\n";
3048 @buffer << s.to_s + "\n";
3014 end
3049 end
3015 end
3050 end
3016
3051
3017 #
3052 #
3018 # Adds unicode fonts.<br>
3053 # Adds unicode fonts.<br>
3019 # Based on PDF Reference 1.3 (section 5)
3054 # Based on PDF Reference 1.3 (section 5)
3020 # @access protected
3055 # @access protected
3021 # @author Nicola Asuni
3056 # @author Nicola Asuni
3022 # @since 1.52.0.TC005 (2005-01-05)
3057 # @since 1.52.0.TC005 (2005-01-05)
3023 #
3058 #
3024 def puttruetypeunicode(font)
3059 def puttruetypeunicode(font)
3025 # Type0 Font
3060 # Type0 Font
3026 # A composite font composed of other fonts, organized hierarchically
3061 # A composite font composed of other fonts, organized hierarchically
3027 newobj();
3062 newobj();
3028 out('<</Type /Font');
3063 out('<</Type /Font');
3029 out('/Subtype /Type0');
3064 out('/Subtype /Type0');
3030 out('/BaseFont /' + font['name'] + '');
3065 out('/BaseFont /' + font['name'] + '');
3031 out('/Encoding /Identity-H'); #The horizontal identity mapping for 2-byte CIDs; may be used with CIDFonts using any Registry, Ordering, and Supplement values.
3066 out('/Encoding /Identity-H'); #The horizontal identity mapping for 2-byte CIDs; may be used with CIDFonts using any Registry, Ordering, and Supplement values.
3032 out('/DescendantFonts [' + (@n + 1).to_s + ' 0 R]');
3067 out('/DescendantFonts [' + (@n + 1).to_s + ' 0 R]');
3033 out('/ToUnicode ' + (@n + 2).to_s + ' 0 R');
3068 out('/ToUnicode ' + (@n + 2).to_s + ' 0 R');
3034 out('>>');
3069 out('>>');
3035 out('endobj');
3070 out('endobj');
3036
3071
3037 # CIDFontType2
3072 # CIDFontType2
3038 # A CIDFont whose glyph descriptions are based on TrueType font technology
3073 # A CIDFont whose glyph descriptions are based on TrueType font technology
3039 newobj();
3074 newobj();
3040 out('<</Type /Font');
3075 out('<</Type /Font');
3041 out('/Subtype /CIDFontType2');
3076 out('/Subtype /CIDFontType2');
3042 out('/BaseFont /' + font['name'] + '');
3077 out('/BaseFont /' + font['name'] + '');
3043 out('/CIDSystemInfo ' + (@n + 2).to_s + ' 0 R');
3078 out('/CIDSystemInfo ' + (@n + 2).to_s + ' 0 R');
3044 out('/FontDescriptor ' + (@n + 3).to_s + ' 0 R');
3079 out('/FontDescriptor ' + (@n + 3).to_s + ' 0 R');
3045 if (!font['desc']['MissingWidth'].nil?)
3080 if (!font['desc']['MissingWidth'].nil?)
3046 out('/DW ' + font['desc']['MissingWidth'].to_s + ''); # The default width for glyphs in the CIDFont MissingWidth
3081 out('/DW ' + font['desc']['MissingWidth'].to_s + ''); # The default width for glyphs in the CIDFont MissingWidth
3047 end
3082 end
3048 w = "";
3083 w = "";
3049 font['cw'].each do |cid, width|
3084 font['cw'].each do |cid, width|
3050 w << '' + cid.to_s + ' [' + width.to_s + '] '; # define a specific width for each individual CID
3085 w << '' + cid.to_s + ' [' + width.to_s + '] '; # define a specific width for each individual CID
3051 end
3086 end
3052 out('/W [' + w + ']'); # A description of the widths for the glyphs in the CIDFont
3087 out('/W [' + w + ']'); # A description of the widths for the glyphs in the CIDFont
3053 out('/CIDToGIDMap ' + (@n + 4).to_s + ' 0 R');
3088 out('/CIDToGIDMap ' + (@n + 4).to_s + ' 0 R');
3054 out('>>');
3089 out('>>');
3055 out('endobj');
3090 out('endobj');
3056
3091
3057 # ToUnicode
3092 # ToUnicode
3058 # is a stream object that contains the definition of the CMap
3093 # is a stream object that contains the definition of the CMap
3059 # (PDF Reference 1.3 chap. 5.9)
3094 # (PDF Reference 1.3 chap. 5.9)
3060 newobj();
3095 newobj();
3061 out('<</Length 383>>');
3096 out('<</Length 383>>');
3062 out('stream');
3097 out('stream');
3063 out('/CIDInit /ProcSet findresource begin');
3098 out('/CIDInit /ProcSet findresource begin');
3064 out('12 dict begin');
3099 out('12 dict begin');
3065 out('begincmap');
3100 out('begincmap');
3066 out('/CIDSystemInfo');
3101 out('/CIDSystemInfo');
3067 out('<</Registry (Adobe)');
3102 out('<</Registry (Adobe)');
3068 out('/Ordering (UCS)');
3103 out('/Ordering (UCS)');
3069 out('/Supplement 0');
3104 out('/Supplement 0');
3070 out('>> def');
3105 out('>> def');
3071 out('/CMapName /Adobe-Identity-UCS def');
3106 out('/CMapName /Adobe-Identity-UCS def');
3072 out('/CMapType 2 def');
3107 out('/CMapType 2 def');
3073 out('1 begincodespacerange');
3108 out('1 begincodespacerange');
3074 out('<0000> <FFFF>');
3109 out('<0000> <FFFF>');
3075 out('endcodespacerange');
3110 out('endcodespacerange');
3076 out('1 beginbfrange');
3111 out('1 beginbfrange');
3077 out('<0000> <FFFF> <0000>');
3112 out('<0000> <FFFF> <0000>');
3078 out('endbfrange');
3113 out('endbfrange');
3079 out('endcmap');
3114 out('endcmap');
3080 out('CMapName currentdict /CMap defineresource pop');
3115 out('CMapName currentdict /CMap defineresource pop');
3081 out('end');
3116 out('end');
3082 out('end');
3117 out('end');
3083 out('endstream');
3118 out('endstream');
3084 out('endobj');
3119 out('endobj');
3085
3120
3086 # CIDSystemInfo dictionary
3121 # CIDSystemInfo dictionary
3087 # A dictionary containing entries that define the character collection of the CIDFont.
3122 # A dictionary containing entries that define the character collection of the CIDFont.
3088 newobj();
3123 newobj();
3089 out('<</Registry (Adobe)'); # A string identifying an issuer of character collections
3124 out('<</Registry (Adobe)'); # A string identifying an issuer of character collections
3090 out('/Ordering (UCS)'); # A string that uniquely names a character collection issued by a specific registry
3125 out('/Ordering (UCS)'); # A string that uniquely names a character collection issued by a specific registry
3091 out('/Supplement 0'); # The supplement number of the character collection.
3126 out('/Supplement 0'); # The supplement number of the character collection.
3092 out('>>');
3127 out('>>');
3093 out('endobj');
3128 out('endobj');
3094
3129
3095 # Font descriptor
3130 # Font descriptor
3096 # A font descriptor describing the CIDFont default metrics other than its glyph widths
3131 # A font descriptor describing the CIDFont default metrics other than its glyph widths
3097 newobj();
3132 newobj();
3098 out('<</Type /FontDescriptor');
3133 out('<</Type /FontDescriptor');
3099 out('/FontName /' + font['name']);
3134 out('/FontName /' + font['name']);
3100 font['desc'].each do |key, value|
3135 font['desc'].each do |key, value|
3101 out('/' + key.to_s + ' ' + value.to_s);
3136 out('/' + key.to_s + ' ' + value.to_s);
3102 end
3137 end
3103 if (font['file'])
3138 if (font['file'])
3104 # A stream containing a TrueType font program
3139 # A stream containing a TrueType font program
3105 out('/FontFile2 ' + @font_files[font['file']]['n'].to_s + ' 0 R');
3140 out('/FontFile2 ' + @font_files[font['file']]['n'].to_s + ' 0 R');
3106 end
3141 end
3107 out('>>');
3142 out('>>');
3108 out('endobj');
3143 out('endobj');
3109
3144
3110 # Embed CIDToGIDMap
3145 # Embed CIDToGIDMap
3111 # A specification of the mapping from CIDs to glyph indices
3146 # A specification of the mapping from CIDs to glyph indices
3112 newobj();
3147 newobj();
3113 ctgfile = getfontpath(font['ctg'])
3148 ctgfile = getfontpath(font['ctg'])
3114 if (!ctgfile)
3149 if (!ctgfile)
3115 Error('Font file not found: ' + ctgfile);
3150 Error('Font file not found: ' + ctgfile);
3116 end
3151 end
3117 size = File.size(ctgfile);
3152 size = File.size(ctgfile);
3118 out('<</Length ' + size.to_s + '');
3153 out('<</Length ' + size.to_s + '');
3119 if (ctgfile[-2,2] == '.z') # check file extension
3154 if (ctgfile[-2,2] == '.z') # check file extension
3120 # Decompresses data encoded using the public-domain
3155 # Decompresses data encoded using the public-domain
3121 # zlib/deflate compression method, reproducing the
3156 # zlib/deflate compression method, reproducing the
3122 # original text or binary data#
3157 # original text or binary data#
3123 out('/Filter /FlateDecode');
3158 out('/Filter /FlateDecode');
3124 end
3159 end
3125 out('>>');
3160 out('>>');
3126 open(ctgfile, "rb") do |f|
3161 open(ctgfile, "rb") do |f|
3127 putstream(f.read())
3162 putstream(f.read())
3128 end
3163 end
3129 out('endobj');
3164 out('endobj');
3130 end
3165 end
3131
3166
3132 #
3167 #
3133 # Converts UTF-8 strings to codepoints array.<br>
3168 # Converts UTF-8 strings to codepoints array.<br>
3134 # Invalid byte sequences will be replaced with 0xFFFD (replacement character)<br>
3169 # Invalid byte sequences will be replaced with 0xFFFD (replacement character)<br>
3135 # Based on: http://www.faqs.org/rfcs/rfc3629.html
3170 # Based on: http://www.faqs.org/rfcs/rfc3629.html
3136 # <pre>
3171 # <pre>
3137 # Char. number range | UTF-8 octet sequence
3172 # Char. number range | UTF-8 octet sequence
3138 # (hexadecimal) | (binary)
3173 # (hexadecimal) | (binary)
3139 # --------------------+-----------------------------------------------
3174 # --------------------+-----------------------------------------------
3140 # 0000 0000-0000 007F | 0xxxxxxx
3175 # 0000 0000-0000 007F | 0xxxxxxx
3141 # 0000 0080-0000 07FF | 110xxxxx 10xxxxxx
3176 # 0000 0080-0000 07FF | 110xxxxx 10xxxxxx
3142 # 0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx
3177 # 0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx
3143 # 0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
3178 # 0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
3144 # ---------------------------------------------------------------------
3179 # ---------------------------------------------------------------------
3145 #
3180 #
3146 # ABFN notation:
3181 # ABFN notation:
3147 # ---------------------------------------------------------------------
3182 # ---------------------------------------------------------------------
3148 # UTF8-octets =#( UTF8-char )
3183 # UTF8-octets =#( UTF8-char )
3149 # UTF8-char = UTF8-1 / UTF8-2 / UTF8-3 / UTF8-4
3184 # UTF8-char = UTF8-1 / UTF8-2 / UTF8-3 / UTF8-4
3150 # UTF8-1 = %x00-7F
3185 # UTF8-1 = %x00-7F
3151 # UTF8-2 = %xC2-DF UTF8-tail
3186 # UTF8-2 = %xC2-DF UTF8-tail
3152 #
3187 #
3153 # UTF8-3 = %xE0 %xA0-BF UTF8-tail / %xE1-EC 2( UTF8-tail ) /
3188 # UTF8-3 = %xE0 %xA0-BF UTF8-tail / %xE1-EC 2( UTF8-tail ) /
3154 # %xED %x80-9F UTF8-tail / %xEE-EF 2( UTF8-tail )
3189 # %xED %x80-9F UTF8-tail / %xEE-EF 2( UTF8-tail )
3155 # UTF8-4 = %xF0 %x90-BF 2( UTF8-tail ) / %xF1-F3 3( UTF8-tail ) /
3190 # UTF8-4 = %xF0 %x90-BF 2( UTF8-tail ) / %xF1-F3 3( UTF8-tail ) /
3156 # %xF4 %x80-8F 2( UTF8-tail )
3191 # %xF4 %x80-8F 2( UTF8-tail )
3157 # UTF8-tail = %x80-BF
3192 # UTF8-tail = %x80-BF
3158 # ---------------------------------------------------------------------
3193 # ---------------------------------------------------------------------
3159 # </pre>
3194 # </pre>
3160 # @param string :str string to process.
3195 # @param string :str string to process.
3161 # @return array containing codepoints (UTF-8 characters values)
3196 # @return array containing codepoints (UTF-8 characters values)
3162 # @access protected
3197 # @access protected
3163 # @author Nicola Asuni
3198 # @author Nicola Asuni
3164 # @since 1.53.0.TC005 (2005-01-05)
3199 # @since 1.53.0.TC005 (2005-01-05)
3165 #
3200 #
3166 def UTF8StringToArray(str)
3201 def UTF8StringToArray(str)
3167 if (!@is_unicode)
3202 if (!@is_unicode)
3168 return str; # string is not in unicode
3203 return str; # string is not in unicode
3169 end
3204 end
3170
3205
3171 unicode = [] # array containing unicode values
3206 unicode = [] # array containing unicode values
3172 bytes = [] # array containing single character byte sequences
3207 bytes = [] # array containing single character byte sequences
3173 numbytes = 1; # number of octetc needed to represent the UTF-8 character
3208 numbytes = 1; # number of octetc needed to represent the UTF-8 character
3174
3209
3175 str = str.to_s; # force :str to be a string
3210 str = str.to_s; # force :str to be a string
3176
3211
3177 str.each_byte do |char|
3212 str.each_byte do |char|
3178 if (bytes.length == 0) # get starting octect
3213 if (bytes.length == 0) # get starting octect
3179 if (char <= 0x7F)
3214 if (char <= 0x7F)
3180 unicode << char # use the character "as is" because is ASCII
3215 unicode << char # use the character "as is" because is ASCII
3181 numbytes = 1
3216 numbytes = 1
3182 elsif ((char >> 0x05) == 0x06) # 2 bytes character (0x06 = 110 BIN)
3217 elsif ((char >> 0x05) == 0x06) # 2 bytes character (0x06 = 110 BIN)
3183 bytes << ((char - 0xC0) << 0x06)
3218 bytes << ((char - 0xC0) << 0x06)
3184 numbytes = 2
3219 numbytes = 2
3185 elsif ((char >> 0x04) == 0x0E) # 3 bytes character (0x0E = 1110 BIN)
3220 elsif ((char >> 0x04) == 0x0E) # 3 bytes character (0x0E = 1110 BIN)
3186 bytes << ((char - 0xE0) << 0x0C)
3221 bytes << ((char - 0xE0) << 0x0C)
3187 numbytes = 3
3222 numbytes = 3
3188 elsif ((char >> 0x03) == 0x1E) # 4 bytes character (0x1E = 11110 BIN)
3223 elsif ((char >> 0x03) == 0x1E) # 4 bytes character (0x1E = 11110 BIN)
3189 bytes << ((char - 0xF0) << 0x12)
3224 bytes << ((char - 0xF0) << 0x12)
3190 numbytes = 4
3225 numbytes = 4
3191 else
3226 else
3192 # use replacement character for other invalid sequences
3227 # use replacement character for other invalid sequences
3193 unicode << 0xFFFD
3228 unicode << 0xFFFD
3194 bytes = []
3229 bytes = []
3195 numbytes = 1
3230 numbytes = 1
3196 end
3231 end
3197 elsif ((char >> 0x06) == 0x02) # bytes 2, 3 and 4 must start with 0x02 = 10 BIN
3232 elsif ((char >> 0x06) == 0x02) # bytes 2, 3 and 4 must start with 0x02 = 10 BIN
3198 bytes << (char - 0x80)
3233 bytes << (char - 0x80)
3199 if (bytes.length == numbytes)
3234 if (bytes.length == numbytes)
3200 # compose UTF-8 bytes to a single unicode value
3235 # compose UTF-8 bytes to a single unicode value
3201 char = bytes[0]
3236 char = bytes[0]
3202 1.upto(numbytes-1) do |j|
3237 1.upto(numbytes-1) do |j|
3203 char += (bytes[j] << ((numbytes - j - 1) * 0x06))
3238 char += (bytes[j] << ((numbytes - j - 1) * 0x06))
3204 end
3239 end
3205 if (((char >= 0xD800) and (char <= 0xDFFF)) or (char >= 0x10FFFF))
3240 if (((char >= 0xD800) and (char <= 0xDFFF)) or (char >= 0x10FFFF))
3206 # The definition of UTF-8 prohibits encoding character numbers between
3241 # The definition of UTF-8 prohibits encoding character numbers between
3207 # U+D800 and U+DFFF, which are reserved for use with the UTF-16
3242 # U+D800 and U+DFFF, which are reserved for use with the UTF-16
3208 # encoding form (as surrogate pairs) and do not directly represent
3243 # encoding form (as surrogate pairs) and do not directly represent
3209 # characters
3244 # characters
3210 unicode << 0xFFFD; # use replacement character
3245 unicode << 0xFFFD; # use replacement character
3211 else
3246 else
3212 unicode << char; # add char to array
3247 unicode << char; # add char to array
3213 end
3248 end
3214 # reset data for next char
3249 # reset data for next char
3215 bytes = []
3250 bytes = []
3216 numbytes = 1;
3251 numbytes = 1;
3217 end
3252 end
3218 else
3253 else
3219 # use replacement character for other invalid sequences
3254 # use replacement character for other invalid sequences
3220 unicode << 0xFFFD;
3255 unicode << 0xFFFD;
3221 bytes = []
3256 bytes = []
3222 numbytes = 1;
3257 numbytes = 1;
3223 end
3258 end
3224 end
3259 end
3225 return unicode;
3260 return unicode;
3226 end
3261 end
3227
3262
3228 #
3263 #
3229 # Converts UTF-8 strings to UTF16-BE.<br>
3264 # Converts UTF-8 strings to UTF16-BE.<br>
3230 # Based on: http://www.faqs.org/rfcs/rfc2781.html
3265 # Based on: http://www.faqs.org/rfcs/rfc2781.html
3231 # <pre>
3266 # <pre>
3232 # Encoding UTF-16:
3267 # Encoding UTF-16:
3233 #
3268 #
3234 # Encoding of a single character from an ISO 10646 character value to
3269 # Encoding of a single character from an ISO 10646 character value to
3235 # UTF-16 proceeds as follows. Let U be the character number, no greater
3270 # UTF-16 proceeds as follows. Let U be the character number, no greater
3236 # than 0x10FFFF.
3271 # than 0x10FFFF.
3237 #
3272 #
3238 # 1) If U < 0x10000, encode U as a 16-bit unsigned integer and
3273 # 1) If U < 0x10000, encode U as a 16-bit unsigned integer and
3239 # terminate.
3274 # terminate.
3240 #
3275 #
3241 # 2) Let U' = U - 0x10000. Because U is less than or equal to 0x10FFFF,
3276 # 2) Let U' = U - 0x10000. Because U is less than or equal to 0x10FFFF,
3242 # U' must be less than or equal to 0xFFFFF. That is, U' can be
3277 # U' must be less than or equal to 0xFFFFF. That is, U' can be
3243 # represented in 20 bits.
3278 # represented in 20 bits.
3244 #
3279 #
3245 # 3) Initialize two 16-bit unsigned integers, W1 and W2, to 0xD800 and
3280 # 3) Initialize two 16-bit unsigned integers, W1 and W2, to 0xD800 and
3246 # 0xDC00, respectively. These integers each have 10 bits free to
3281 # 0xDC00, respectively. These integers each have 10 bits free to
3247 # encode the character value, for a total of 20 bits.
3282 # encode the character value, for a total of 20 bits.
3248 #
3283 #
3249 # 4) Assign the 10 high-order bits of the 20-bit U' to the 10 low-order
3284 # 4) Assign the 10 high-order bits of the 20-bit U' to the 10 low-order
3250 # bits of W1 and the 10 low-order bits of U' to the 10 low-order
3285 # bits of W1 and the 10 low-order bits of U' to the 10 low-order
3251 # bits of W2. Terminate.
3286 # bits of W2. Terminate.
3252 #
3287 #
3253 # Graphically, steps 2 through 4 look like:
3288 # Graphically, steps 2 through 4 look like:
3254 # U' = yyyyyyyyyyxxxxxxxxxx
3289 # U' = yyyyyyyyyyxxxxxxxxxx
3255 # W1 = 110110yyyyyyyyyy
3290 # W1 = 110110yyyyyyyyyy
3256 # W2 = 110111xxxxxxxxxx
3291 # W2 = 110111xxxxxxxxxx
3257 # </pre>
3292 # </pre>
3258 # @param string :str string to process.
3293 # @param string :str string to process.
3259 # @param boolean :setbom if true set the Byte Order Mark (BOM = 0xFEFF)
3294 # @param boolean :setbom if true set the Byte Order Mark (BOM = 0xFEFF)
3260 # @return string
3295 # @return string
3261 # @access protected
3296 # @access protected
3262 # @author Nicola Asuni
3297 # @author Nicola Asuni
3263 # @since 1.53.0.TC005 (2005-01-05)
3298 # @since 1.53.0.TC005 (2005-01-05)
3264 # @uses UTF8StringToArray
3299 # @uses UTF8StringToArray
3265 #
3300 #
3266 def UTF8ToUTF16BE(str, setbom=true)
3301 def UTF8ToUTF16BE(str, setbom=true)
3267 if (!@is_unicode)
3302 if (!@is_unicode)
3268 return str; # string is not in unicode
3303 return str; # string is not in unicode
3269 end
3304 end
3270 outstr = ""; # string to be returned
3305 outstr = ""; # string to be returned
3271 unicode = UTF8StringToArray(str); # array containing UTF-8 unicode values
3306 unicode = UTF8StringToArray(str); # array containing UTF-8 unicode values
3272 numitems = unicode.length;
3307 numitems = unicode.length;
3273
3308
3274 if (setbom)
3309 if (setbom)
3275 outstr << "\xFE\xFF"; # Byte Order Mark (BOM)
3310 outstr << "\xFE\xFF"; # Byte Order Mark (BOM)
3276 end
3311 end
3277 unicode.each do |char|
3312 unicode.each do |char|
3278 if (char == 0xFFFD)
3313 if (char == 0xFFFD)
3279 outstr << "\xFF\xFD"; # replacement character
3314 outstr << "\xFF\xFD"; # replacement character
3280 elsif (char < 0x10000)
3315 elsif (char < 0x10000)
3281 outstr << (char >> 0x08).chr;
3316 outstr << (char >> 0x08).chr;
3282 outstr << (char & 0xFF).chr;
3317 outstr << (char & 0xFF).chr;
3283 else
3318 else
3284 char -= 0x10000;
3319 char -= 0x10000;
3285 w1 = 0xD800 | (char >> 0x10);
3320 w1 = 0xD800 | (char >> 0x10);
3286 w2 = 0xDC00 | (char & 0x3FF);
3321 w2 = 0xDC00 | (char & 0x3FF);
3287 outstr << (w1 >> 0x08).chr;
3322 outstr << (w1 >> 0x08).chr;
3288 outstr << (w1 & 0xFF).chr;
3323 outstr << (w1 & 0xFF).chr;
3289 outstr << (w2 >> 0x08).chr;
3324 outstr << (w2 >> 0x08).chr;
3290 outstr << (w2 & 0xFF).chr;
3325 outstr << (w2 & 0xFF).chr;
3291 end
3326 end
3292 end
3327 end
3293 return outstr;
3328 return outstr;
3294 end
3329 end
3295
3330
3296 # ====================================================
3331 # ====================================================
3297
3332
3298 #
3333 #
3299 # Set header font.
3334 # Set header font.
3300 # @param array :font font
3335 # @param array :font font
3301 # @since 1.1
3336 # @since 1.1
3302 #
3337 #
3303 def SetHeaderFont(font)
3338 def SetHeaderFont(font)
3304 @header_font = font;
3339 @header_font = font;
3305 end
3340 end
3306 alias_method :set_header_font, :SetHeaderFont
3341 alias_method :set_header_font, :SetHeaderFont
3307
3342
3308 #
3343 #
3309 # Set footer font.
3344 # Set footer font.
3310 # @param array :font font
3345 # @param array :font font
3311 # @since 1.1
3346 # @since 1.1
3312 #
3347 #
3313 def SetFooterFont(font)
3348 def SetFooterFont(font)
3314 @footer_font = font;
3349 @footer_font = font;
3315 end
3350 end
3316 alias_method :set_footer_font, :SetFooterFont
3351 alias_method :set_footer_font, :SetFooterFont
3317
3352
3318 #
3353 #
3319 # Set language array.
3354 # Set language array.
3320 # @param array :language
3355 # @param array :language
3321 # @since 1.1
3356 # @since 1.1
3322 #
3357 #
3323 def SetLanguageArray(language)
3358 def SetLanguageArray(language)
3324 @l = language;
3359 @l = language;
3325 end
3360 end
3326 alias_method :set_language_array, :SetLanguageArray
3361 alias_method :set_language_array, :SetLanguageArray
3327 #
3362 #
3328 # Set document barcode.
3363 # Set document barcode.
3329 # @param string :bc barcode
3364 # @param string :bc barcode
3330 #
3365 #
3331 def SetBarcode(bc="")
3366 def SetBarcode(bc="")
3332 @barcode = bc;
3367 @barcode = bc;
3333 end
3368 end
3334
3369
3335 #
3370 #
3336 # Print Barcode.
3371 # Print Barcode.
3337 # @param int :x x position in user units
3372 # @param int :x x position in user units
3338 # @param int :y y position in user units
3373 # @param int :y y position in user units
3339 # @param int :w width in user units
3374 # @param int :w width in user units
3340 # @param int :h height position in user units
3375 # @param int :h height position in user units
3341 # @param string :type type of barcode (I25, C128A, C128B, C128C, C39)
3376 # @param string :type type of barcode (I25, C128A, C128B, C128C, C39)
3342 # @param string :style barcode style
3377 # @param string :style barcode style
3343 # @param string :font font for text
3378 # @param string :font font for text
3344 # @param int :xres x resolution
3379 # @param int :xres x resolution
3345 # @param string :code code to print
3380 # @param string :code code to print
3346 #
3381 #
3347 def writeBarcode(x, y, w, h, type, style, font, xres, code)
3382 def writeBarcode(x, y, w, h, type, style, font, xres, code)
3348 require(File.dirname(__FILE__) + "/barcode/barcode.rb");
3383 require(File.dirname(__FILE__) + "/barcode/barcode.rb");
3349 require(File.dirname(__FILE__) + "/barcode/i25object.rb");
3384 require(File.dirname(__FILE__) + "/barcode/i25object.rb");
3350 require(File.dirname(__FILE__) + "/barcode/c39object.rb");
3385 require(File.dirname(__FILE__) + "/barcode/c39object.rb");
3351 require(File.dirname(__FILE__) + "/barcode/c128aobject.rb");
3386 require(File.dirname(__FILE__) + "/barcode/c128aobject.rb");
3352 require(File.dirname(__FILE__) + "/barcode/c128bobject.rb");
3387 require(File.dirname(__FILE__) + "/barcode/c128bobject.rb");
3353 require(File.dirname(__FILE__) + "/barcode/c128cobject.rb");
3388 require(File.dirname(__FILE__) + "/barcode/c128cobject.rb");
3354
3389
3355 if (code.empty?)
3390 if (code.empty?)
3356 return;
3391 return;
3357 end
3392 end
3358
3393
3359 if (style.empty?)
3394 if (style.empty?)
3360 style = BCS_ALIGN_LEFT;
3395 style = BCS_ALIGN_LEFT;
3361 style |= BCS_IMAGE_PNG;
3396 style |= BCS_IMAGE_PNG;
3362 style |= BCS_TRANSPARENT;
3397 style |= BCS_TRANSPARENT;
3363 #:style |= BCS_BORDER;
3398 #:style |= BCS_BORDER;
3364 #:style |= BCS_DRAW_TEXT;
3399 #:style |= BCS_DRAW_TEXT;
3365 #:style |= BCS_STRETCH_TEXT;
3400 #:style |= BCS_STRETCH_TEXT;
3366 #:style |= BCS_REVERSE_COLOR;
3401 #:style |= BCS_REVERSE_COLOR;
3367 end
3402 end
3368 if (font.empty?) then font = BCD_DEFAULT_FONT; end
3403 if (font.empty?) then font = BCD_DEFAULT_FONT; end
3369 if (xres.empty?) then xres = BCD_DEFAULT_XRES; end
3404 if (xres.empty?) then xres = BCD_DEFAULT_XRES; end
3370
3405
3371 scale_factor = 1.5 * xres * @k;
3406 scale_factor = 1.5 * xres * @k;
3372 bc_w = (w * scale_factor).round #width in points
3407 bc_w = (w * scale_factor).round #width in points
3373 bc_h = (h * scale_factor).round #height in points
3408 bc_h = (h * scale_factor).round #height in points
3374
3409
3375 case (type.upcase)
3410 case (type.upcase)
3376 when "I25"
3411 when "I25"
3377 obj = I25Object.new(bc_w, bc_h, style, code);
3412 obj = I25Object.new(bc_w, bc_h, style, code);
3378 when "C128A"
3413 when "C128A"
3379 obj = C128AObject.new(bc_w, bc_h, style, code);
3414 obj = C128AObject.new(bc_w, bc_h, style, code);
3380 when "C128B"
3415 when "C128B"
3381 obj = C128BObject.new(bc_w, bc_h, style, code);
3416 obj = C128BObject.new(bc_w, bc_h, style, code);
3382 when "C128C"
3417 when "C128C"
3383 obj = C128CObject.new(bc_w, bc_h, style, code);
3418 obj = C128CObject.new(bc_w, bc_h, style, code);
3384 when "C39"
3419 when "C39"
3385 obj = C39Object.new(bc_w, bc_h, style, code);
3420 obj = C39Object.new(bc_w, bc_h, style, code);
3386 end
3421 end
3387
3422
3388 obj.SetFont(font);
3423 obj.SetFont(font);
3389 obj.DrawObject(xres);
3424 obj.DrawObject(xres);
3390
3425
3391 #use a temporary file....
3426 #use a temporary file....
3392 tmpName = tempnam(@@k_path_cache,'img');
3427 tmpName = tempnam(@@k_path_cache,'img');
3393 imagepng(obj.getImage(), tmpName);
3428 imagepng(obj.getImage(), tmpName);
3394 Image(tmpName, x, y, w, h, 'png');
3429 Image(tmpName, x, y, w, h, 'png');
3395 obj.DestroyObject();
3430 obj.DestroyObject();
3396 obj = nil
3431 obj = nil
3397 unlink(tmpName);
3432 unlink(tmpName);
3398 end
3433 end
3399
3434
3400 #
3435 #
3401 # Returns the PDF data.
3436 # Returns the PDF data.
3402 #
3437 #
3403 def GetPDFData()
3438 def GetPDFData()
3404 if (@state < 3)
3439 if (@state < 3)
3405 Close();
3440 Close();
3406 end
3441 end
3407 return @buffer;
3442 return @buffer;
3408 end
3443 end
3409
3444
3410 # --- HTML PARSER FUNCTIONS ---
3445 # --- HTML PARSER FUNCTIONS ---
3411
3446
3412 #
3447 #
3413 # Allows to preserve some HTML formatting.<br />
3448 # Allows to preserve some HTML formatting.<br />
3414 # Supports: h1, h2, h3, h4, h5, h6, b, u, i, a, img, p, br, strong, em, ins, del, font, blockquote, li, ul, ol, hr, td, th, tr, table, sup, sub, small
3449 # Supports: h1, h2, h3, h4, h5, h6, b, u, i, a, img, p, br, strong, em, ins, del, font, blockquote, li, ul, ol, hr, td, th, tr, table, sup, sub, small
3415 # @param string :html text to display
3450 # @param string :html text to display
3416 # @param boolean :ln if true add a new line after text (default = true)
3451 # @param boolean :ln if true add a new line after text (default = true)
3417 # @param int :fill Indicates if the background must be painted (1) or transparent (0). Default value: 0.
3452 # @param int :fill Indicates if the background must be painted (1) or transparent (0). Default value: 0.
3418 #
3453 #
3419 def writeHTML(html, ln=true, fill=0, h=0)
3454 def writeHTML(html, ln=true, fill=0, h=0)
3420
3455
3421 @lasth = h if h > 0
3456 @lasth = h if h > 0
3422 if (@lasth == 0)
3457 if (@lasth == 0)
3423 #set row height
3458 #set row height
3424 @lasth = @font_size * @@k_cell_height_ratio;
3459 @lasth = @font_size * @@k_cell_height_ratio;
3425 end
3460 end
3426
3461
3427 @href = nil
3462 @href = nil
3428 @style = "";
3463 @style = "";
3429 @t_cells = [[]];
3464 @t_cells = [[]];
3430 @table_id = 0;
3465 @table_id = 0;
3431
3466
3432 # pre calculate
3467 # pre calculate
3433 html.split(/(<[^>]+>)/).each do |element|
3468 html.split(/(<[^>]+>)/).each do |element|
3434 if "<" == element[0,1]
3469 if "<" == element[0,1]
3435 #Tag
3470 #Tag
3436 if (element[1, 1] == '/')
3471 if (element[1, 1] == '/')
3437 closedHTMLTagCalc(element[2..-2].downcase);
3472 closedHTMLTagCalc(element[2..-2].downcase);
3438 else
3473 else
3439 #Extract attributes
3474 #Extract attributes
3440 # get tag name
3475 # get tag name
3441 tag = element.scan(/([a-zA-Z0-9]*)/).flatten.delete_if {|x| x.length == 0}
3476 tag = element.scan(/([a-zA-Z0-9]*)/).flatten.delete_if {|x| x.length == 0}
3442 tag = tag[0].downcase;
3477 tag = tag[0].downcase;
3443
3478
3444 # get attributes
3479 # get attributes
3445 attr_array = element.scan(/([^=\s]*)=["\']?([^"\']*)["\']?/)
3480 attr_array = element.scan(/([^=\s]*)=["\']?([^"\']*)["\']?/)
3446 attrs = {}
3481 attrs = {}
3447 attr_array.each do |name, value|
3482 attr_array.each do |name, value|
3448 attrs[name.downcase] = value;
3483 attrs[name.downcase] = value;
3449 end
3484 end
3450 openHTMLTagCalc(tag, attrs);
3485 openHTMLTagCalc(tag, attrs);
3451 end
3486 end
3452 end
3487 end
3453 end
3488 end
3454 @table_id = 0;
3489 @table_id = 0;
3455
3490
3456 html.split(/(<[A-Za-z!?\/][^>]*?>)/).each do |element|
3491 html.split(/(<[A-Za-z!?\/][^>]*?>)/).each do |element|
3457 if "<" == element[0,1]
3492 if "<" == element[0,1]
3458 #Tag
3493 #Tag
3459 if (element[1, 1] == '/')
3494 if (element[1, 1] == '/')
3460 closedHTMLTagHandler(element[2..-2].downcase);
3495 closedHTMLTagHandler(element[2..-2].downcase);
3461 else
3496 else
3462 #Extract attributes
3497 #Extract attributes
3463 # get tag name
3498 # get tag name
3464 tag = element.scan(/([a-zA-Z0-9]*)/).flatten.delete_if {|x| x.length == 0}
3499 tag = element.scan(/([a-zA-Z0-9]*)/).flatten.delete_if {|x| x.length == 0}
3465 tag = tag[0].downcase;
3500 tag = tag[0].downcase;
3466
3501
3467 # get attributes
3502 # get attributes
3468 attr_array = element.scan(/([^=\s]*)=["\']?([^"\']*)["\']?/)
3503 attr_array = element.scan(/([^=\s]*)=["\']?([^"\']*)["\']?/)
3469 attrs = {}
3504 attrs = {}
3470 attr_array.each do |name, value|
3505 attr_array.each do |name, value|
3471 attrs[name.downcase] = value;
3506 attrs[name.downcase] = value;
3472 end
3507 end
3473 openHTMLTagHandler(tag, attrs, fill);
3508 openHTMLTagHandler(tag, attrs, fill);
3474 end
3509 end
3475
3510
3476 else
3511 else
3477 #Text
3512 #Text
3478 if (@href)
3513 if (@href)
3479 element.gsub!(/[\t\r\n\f]/, "");
3514 element.gsub!(/[\t\r\n\f]/, "");
3480 addHtmlLink(@href, element, fill);
3515 addHtmlLink(@href, element, fill);
3481 elsif (@tdbegin)
3516 elsif (@tdbegin)
3482 element.gsub!(/[\t\r\n\f]/, "");
3517 element.gsub!(/[\t\r\n\f]/, "");
3483 element.gsub!(/&nbsp;/, " ");
3518 element.gsub!(/&nbsp;/, " ");
3484 base_page = @page;
3519 base_page = @page;
3485 base_x = @x;
3520 base_x = @x;
3486 base_y = @y;
3521 base_y = @y;
3487
3522
3488 MultiCell(@tdwidth, @tdheight, unhtmlentities(element.strip), @tableborder, @tdalign, @tdfill, 1);
3523 MultiCell(@tdwidth, @tdheight, unhtmlentities(element.strip), @tableborder, @tdalign, @tdfill, 1);
3489 tr_end = @t_cells[@table_id][@tr_id][@td_id]['j1'] + 1;
3524 tr_end = @t_cells[@table_id][@tr_id][@td_id]['j1'] + 1;
3490 if @max_td_page[tr_end].nil? or (@max_td_page[tr_end] < @page)
3525 if @max_td_page[tr_end].nil? or (@max_td_page[tr_end] < @page)
3491 @max_td_page[tr_end] = @page
3526 @max_td_page[tr_end] = @page
3492 @max_td_y[tr_end] = @y
3527 @max_td_y[tr_end] = @y
3493 elsif (@max_td_page[tr_end] == @page)
3528 elsif (@max_td_page[tr_end] == @page)
3494 @max_td_y[tr_end] = @y if @max_td_y[tr_end].nil? or (@max_td_y[tr_end] < @y)
3529 @max_td_y[tr_end] = @y if @max_td_y[tr_end].nil? or (@max_td_y[tr_end] < @y)
3495 end
3530 end
3496
3531
3497 @page = base_page;
3532 @page = base_page;
3498 @x = base_x + @tdwidth;
3533 @x = base_x + @tdwidth;
3499 @y = base_y;
3534 @y = base_y;
3500 elsif (element.strip.length > 0)
3535 elsif (element.strip.length > 0)
3501 if @pre_state != true
3536 if @pre_state != true
3502 element.gsub!(/[\t\r\n\f]/, "");
3537 element.gsub!(/[\t\r\n\f]/, "");
3503 element.gsub!(/&nbsp;/, " ");
3538 element.gsub!(/&nbsp;/, " ");
3504 end
3539 end
3505 Write(@lasth, unhtmlentities(element), '', fill);
3540 Write(@lasth, unhtmlentities(element), '', fill);
3506 end
3541 end
3507 end
3542 end
3508 end
3543 end
3509
3544
3510 if (ln)
3545 if (ln)
3511 Ln(@lasth);
3546 Ln(@lasth);
3512 end
3547 end
3513 end
3548 end
3514 alias_method :write_html, :writeHTML
3549 alias_method :write_html, :writeHTML
3515
3550
3516 #
3551 #
3517 # Prints a cell (rectangular area) with optional borders, background color and html text string. The upper-left corner of the cell corresponds to the current position. After the call, the current position moves to the right or to the next line.<br />
3552 # Prints a cell (rectangular area) with optional borders, background color and html text string. The upper-left corner of the cell corresponds to the current position. After the call, the current position moves to the right or to the next line.<br />
3518 # If automatic page breaking is enabled and the cell goes beyond the limit, a page break is done before outputting.
3553 # If automatic page breaking is enabled and the cell goes beyond the limit, a page break is done before outputting.
3519 # @param float :w Cell width. If 0, the cell extends up to the right margin.
3554 # @param float :w Cell width. If 0, the cell extends up to the right margin.
3520 # @param float :h Cell minimum height. The cell extends automatically if needed.
3555 # @param float :h Cell minimum height. The cell extends automatically if needed.
3521 # @param float :x upper-left corner X coordinate
3556 # @param float :x upper-left corner X coordinate
3522 # @param float :y upper-left corner Y coordinate
3557 # @param float :y upper-left corner Y coordinate
3523 # @param string :html html text to print. Default value: empty string.
3558 # @param string :html html text to print. Default value: empty string.
3524 # @param mixed :border Indicates if borders must be drawn around the cell. The value can be either a number:<ul><li>0: no border (default)</li><li>1: frame</li></ul>or a string containing some or all of the following characters (in any order):<ul><li>L: left</li><li>T: top</li><li>R: right</li><li>B: bottom</li></ul>
3559 # @param mixed :border Indicates if borders must be drawn around the cell. The value can be either a number:<ul><li>0: no border (default)</li><li>1: frame</li></ul>or a string containing some or all of the following characters (in any order):<ul><li>L: left</li><li>T: top</li><li>R: right</li><li>B: bottom</li></ul>
3525 # @param int :ln Indicates where the current position should go after the call. Possible values are:<ul><li>0: to the right</li><li>1: to the beginning of the next line</li><li>2: below</li></ul>
3560 # @param int :ln Indicates where the current position should go after the call. Possible values are:<ul><li>0: to the right</li><li>1: to the beginning of the next line</li><li>2: below</li></ul>
3526 # Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: 0.
3561 # Putting 1 is equivalent to putting 0 and calling Ln() just after. Default value: 0.
3527 # @param int :fill Indicates if the cell background must be painted (1) or transparent (0). Default value: 0.
3562 # @param int :fill Indicates if the cell background must be painted (1) or transparent (0). Default value: 0.
3528 # @see Cell()
3563 # @see Cell()
3529 #
3564 #
3530 def writeHTMLCell(w, h, x, y, html='', border=0, ln=1, fill=0)
3565 def writeHTMLCell(w, h, x, y, html='', border=0, ln=1, fill=0)
3531
3566
3532 if (@lasth == 0)
3567 if (@lasth == 0)
3533 #set row height
3568 #set row height
3534 @lasth = @font_size * @@k_cell_height_ratio;
3569 @lasth = @font_size * @@k_cell_height_ratio;
3535 end
3570 end
3536
3571
3537 if (x == 0)
3572 if (x == 0)
3538 x = GetX();
3573 x = GetX();
3539 end
3574 end
3540 if (y == 0)
3575 if (y == 0)
3541 y = GetY();
3576 y = GetY();
3542 end
3577 end
3543
3578
3544 # get current page number
3579 # get current page number
3545 pagenum = @page;
3580 pagenum = @page;
3546
3581
3547 SetX(x);
3582 SetX(x);
3548 SetY(y);
3583 SetY(y);
3549
3584
3550 if (w == 0)
3585 if (w == 0)
3551 w = @fw - x - @r_margin;
3586 w = @fw - x - @r_margin;
3552 end
3587 end
3553
3588
3554 b=0;
3589 b=0;
3555 if (border)
3590 if (border)
3556 if (border==1)
3591 if (border==1)
3557 border='LTRB';
3592 border='LTRB';
3558 b='LRT';
3593 b='LRT';
3559 b2='LR';
3594 b2='LR';
3560 elsif border.is_a?(String)
3595 elsif border.is_a?(String)
3561 b2='';
3596 b2='';
3562 if (border.include?('L'))
3597 if (border.include?('L'))
3563 b2<<'L';
3598 b2<<'L';
3564 end
3599 end
3565 if (border.include?('R'))
3600 if (border.include?('R'))
3566 b2<<'R';
3601 b2<<'R';
3567 end
3602 end
3568 b=(border.include?('T')) ? b2 + 'T' : b2;
3603 b=(border.include?('T')) ? b2 + 'T' : b2;
3569 end
3604 end
3570 end
3605 end
3571
3606
3572 # store original margin values
3607 # store original margin values
3573 l_margin = @l_margin;
3608 l_margin = @l_margin;
3574 r_margin = @r_margin;
3609 r_margin = @r_margin;
3575
3610
3576 # set new margin values
3611 # set new margin values
3577 SetLeftMargin(x);
3612 SetLeftMargin(x);
3578 SetRightMargin(@fw - x - w);
3613 SetRightMargin(@fw - x - w);
3579
3614
3580 # calculate remaining vertical space on page
3615 # calculate remaining vertical space on page
3581 restspace = GetPageHeight() - GetY() - GetBreakMargin();
3616 restspace = GetPageHeight() - GetY() - GetBreakMargin();
3582
3617
3583 writeHTML(html, true, fill); # write html text
3618 writeHTML(html, true, fill); # write html text
3584
3619
3585 currentY = GetY();
3620 currentY = GetY();
3586
3621
3587 @auto_page_break = false;
3622 @auto_page_break = false;
3588 # check if a new page has been created
3623 # check if a new page has been created
3589 if (@page > pagenum)
3624 if (@page > pagenum)
3590 # design a cell around the text on first page
3625 # design a cell around the text on first page
3591 currentpage = @page;
3626 currentpage = @page;
3592 @page = pagenum;
3627 @page = pagenum;
3593 SetY(GetPageHeight() - restspace - GetBreakMargin());
3628 SetY(GetPageHeight() - restspace - GetBreakMargin());
3594 Cell(w, restspace - 1, "", b, 0, 'L', 0);
3629 Cell(w, restspace - 1, "", b, 0, 'L', 0);
3595 b = b2;
3630 b = b2;
3596 @page += 1;
3631 @page += 1;
3597 while @page < currentpage
3632 while @page < currentpage
3598 SetY(@t_margin); # put cursor at the beginning of text
3633 SetY(@t_margin); # put cursor at the beginning of text
3599 Cell(w, @page_break_trigger - @t_margin, "", b, 0, 'L', 0);
3634 Cell(w, @page_break_trigger - @t_margin, "", b, 0, 'L', 0);
3600 @page += 1;
3635 @page += 1;
3601 end
3636 end
3602 if (border.is_a?(String) and border.include?('B'))
3637 if (border.is_a?(String) and border.include?('B'))
3603 b<<'B';
3638 b<<'B';
3604 end
3639 end
3605 # design a cell around the text on last page
3640 # design a cell around the text on last page
3606 SetY(@t_margin); # put cursor at the beginning of text
3641 SetY(@t_margin); # put cursor at the beginning of text
3607 Cell(w, currentY - @t_margin, "", b, 0, 'L', 0);
3642 Cell(w, currentY - @t_margin, "", b, 0, 'L', 0);
3608 else
3643 else
3609 SetY(y); # put cursor at the beginning of text
3644 SetY(y); # put cursor at the beginning of text
3610 # design a cell around the text
3645 # design a cell around the text
3611 Cell(w, [h, (currentY - y)].max, "", border, 0, 'L', 0);
3646 Cell(w, [h, (currentY - y)].max, "", border, 0, 'L', 0);
3612 end
3647 end
3613 @auto_page_break = true;
3648 @auto_page_break = true;
3614
3649
3615 # restore original margin values
3650 # restore original margin values
3616 SetLeftMargin(l_margin);
3651 SetLeftMargin(l_margin);
3617 SetRightMargin(r_margin);
3652 SetRightMargin(r_margin);
3618
3653
3619 @lasth = h
3654 @lasth = h
3620
3655
3621 # move cursor to specified position
3656 # move cursor to specified position
3622 if (ln == 0)
3657 if (ln == 0)
3623 # go to the top-right of the cell
3658 # go to the top-right of the cell
3624 @x = x + w;
3659 @x = x + w;
3625 @y = y;
3660 @y = y;
3626 elsif (ln == 1)
3661 elsif (ln == 1)
3627 # go to the beginning of the next line
3662 # go to the beginning of the next line
3628 @x = @l_margin;
3663 @x = @l_margin;
3629 @y = currentY;
3664 @y = currentY;
3630 elsif (ln == 2)
3665 elsif (ln == 2)
3631 # go to the bottom-left of the cell (below)
3666 # go to the bottom-left of the cell (below)
3632 @x = x;
3667 @x = x;
3633 @y = currentY;
3668 @y = currentY;
3634 end
3669 end
3635 end
3670 end
3636 alias_method :write_html_cell, :writeHTMLCell
3671 alias_method :write_html_cell, :writeHTMLCell
3637
3672
3638 #
3673 #
3639 # Check html table tag position.
3674 # Check html table tag position.
3640 #
3675 #
3641 # @param array :table potision array
3676 # @param array :table potision array
3642 # @param int :current tr tag id number
3677 # @param int :current tr tag id number
3643 # @param int :current td tag id number
3678 # @param int :current td tag id number
3644 # @access private
3679 # @access private
3645 # @return int : next td_id position.
3680 # @return int : next td_id position.
3646 # value 0 mean that can use position.
3681 # value 0 mean that can use position.
3647 #
3682 #
3648 def checkTableBlockingCellPosition(table, tr_id, td_id )
3683 def checkTableBlockingCellPosition(table, tr_id, td_id )
3649 0.upto(tr_id) do |j|
3684 0.upto(tr_id) do |j|
3650 0.upto(@t_cells[table][j].size - 1) do |i|
3685 0.upto(@t_cells[table][j].size - 1) do |i|
3651 if @t_cells[table][j][i]['i0'] <= td_id and td_id <= @t_cells[table][j][i]['i1']
3686 if @t_cells[table][j][i]['i0'] <= td_id and td_id <= @t_cells[table][j][i]['i1']
3652 if @t_cells[table][j][i]['j0'] <= tr_id and tr_id <= @t_cells[table][j][i]['j1']
3687 if @t_cells[table][j][i]['j0'] <= tr_id and tr_id <= @t_cells[table][j][i]['j1']
3653 return @t_cells[table][j][i]['i1'] - td_id + 1;
3688 return @t_cells[table][j][i]['i1'] - td_id + 1;
3654 end
3689 end
3655 end
3690 end
3656 end
3691 end
3657 end
3692 end
3658 return 0;
3693 return 0;
3659 end
3694 end
3660
3695
3661 #
3696 #
3662 # Calculate opening tags.
3697 # Calculate opening tags.
3663 #
3698 #
3664 # html table cell array : @t_cells
3699 # html table cell array : @t_cells
3665 #
3700 #
3666 # i0: table cell start position
3701 # i0: table cell start position
3667 # i1: table cell end position
3702 # i1: table cell end position
3668 # j0: table row start position
3703 # j0: table row start position
3669 # j1: table row end position
3704 # j1: table row end position
3670 #
3705 #
3671 # +------+
3706 # +------+
3672 # |i0,j0 |
3707 # |i0,j0 |
3673 # | i1,j1|
3708 # | i1,j1|
3674 # +------+
3709 # +------+
3675 #
3710 #
3676 # example html:
3711 # example html:
3677 # <table>
3712 # <table>
3678 # <tr><td></td><td></td><td></td></tr>
3713 # <tr><td></td><td></td><td></td></tr>
3679 # <tr><td colspan=2></td><td></td></tr>
3714 # <tr><td colspan=2></td><td></td></tr>
3680 # <tr><td rowspan=2></td><td></td><td></td></tr>
3715 # <tr><td rowspan=2></td><td></td><td></td></tr>
3681 # <tr><td></td><td></td></tr>
3716 # <tr><td></td><td></td></tr>
3682 # </table>
3717 # </table>
3683 #
3718 #
3684 # i: 0 1 2
3719 # i: 0 1 2
3685 # j+----+----+----+
3720 # j+----+----+----+
3686 # :|0,0 |1,0 |2,0 |
3721 # :|0,0 |1,0 |2,0 |
3687 # 0| 0,0| 1,0| 2,0|
3722 # 0| 0,0| 1,0| 2,0|
3688 # +----+----+----+
3723 # +----+----+----+
3689 # |0,1 |2,1 |
3724 # |0,1 |2,1 |
3690 # 1| 1,1| 2,1|
3725 # 1| 1,1| 2,1|
3691 # +----+----+----+
3726 # +----+----+----+
3692 # |0,2 |1,2 |2,2 |
3727 # |0,2 |1,2 |2,2 |
3693 # 2| | 1,2| 2,2|
3728 # 2| | 1,2| 2,2|
3694 # + +----+----+
3729 # + +----+----+
3695 # | |1,3 |2,3 |
3730 # | |1,3 |2,3 |
3696 # 3| 0,3| 1,3| 2,3|
3731 # 3| 0,3| 1,3| 2,3|
3697 # +----+----+----+
3732 # +----+----+----+
3698 #
3733 #
3699 # html table cell array :
3734 # html table cell array :
3700 # [[[i0=>0,j0=>0,i1=>0,j1=>0],[i0=>1,j0=>0,i1=>1,j1=>0],[i0=>2,j0=>0,i1=>2,j1=>0]],
3735 # [[[i0=>0,j0=>0,i1=>0,j1=>0],[i0=>1,j0=>0,i1=>1,j1=>0],[i0=>2,j0=>0,i1=>2,j1=>0]],
3701 # [[i0=>0,j0=>1,i1=>1,j1=>1],[i0=>2,j0=>1,i1=>2,j1=>1]],
3736 # [[i0=>0,j0=>1,i1=>1,j1=>1],[i0=>2,j0=>1,i1=>2,j1=>1]],
3702 # [[i0=>0,j0=>2,i1=>0,j1=>3],[i0=>1,j0=>2,i1=>1,j1=>2],[i0=>2,j0=>2,i1=>2,j1=>2]]
3737 # [[i0=>0,j0=>2,i1=>0,j1=>3],[i0=>1,j0=>2,i1=>1,j1=>2],[i0=>2,j0=>2,i1=>2,j1=>2]]
3703 # [[i0=>1,j0=>3,i1=>1,j1=>3],[i0=>2,j0=>3,i1=>2,j1=>3]]]
3738 # [[i0=>1,j0=>3,i1=>1,j1=>3],[i0=>2,j0=>3,i1=>2,j1=>3]]]
3704 #
3739 #
3705 # @param string :tag tag name (in upcase)
3740 # @param string :tag tag name (in upcase)
3706 # @param string :attr tag attribute (in upcase)
3741 # @param string :attr tag attribute (in upcase)
3707 # @access private
3742 # @access private
3708 #
3743 #
3709 def openHTMLTagCalc(tag, attrs)
3744 def openHTMLTagCalc(tag, attrs)
3710 #Opening tag
3745 #Opening tag
3711 case (tag)
3746 case (tag)
3712 when 'table'
3747 when 'table'
3713 @max_table_columns[@table_id] = 0;
3748 @max_table_columns[@table_id] = 0;
3714 @t_columns = 0;
3749 @t_columns = 0;
3715 @tr_id = -1;
3750 @tr_id = -1;
3716 when 'tr'
3751 when 'tr'
3717 if @max_table_columns[@table_id] < @t_columns
3752 if @max_table_columns[@table_id] < @t_columns
3718 @max_table_columns[@table_id] = @t_columns;
3753 @max_table_columns[@table_id] = @t_columns;
3719 end
3754 end
3720 @t_columns = 0;
3755 @t_columns = 0;
3721 @tr_id += 1;
3756 @tr_id += 1;
3722 @td_id = -1;
3757 @td_id = -1;
3723 @t_cells[@table_id].push []
3758 @t_cells[@table_id].push []
3724 when 'td', 'th'
3759 when 'td', 'th'
3725 @td_id += 1;
3760 @td_id += 1;
3726 if attrs['colspan'].nil? or attrs['colspan'] == ''
3761 if attrs['colspan'].nil? or attrs['colspan'] == ''
3727 colspan = 1;
3762 colspan = 1;
3728 else
3763 else
3729 colspan = attrs['colspan'].to_i;
3764 colspan = attrs['colspan'].to_i;
3730 end
3765 end
3731 if attrs['rowspan'].nil? or attrs['rowspan'] == ''
3766 if attrs['rowspan'].nil? or attrs['rowspan'] == ''
3732 rowspan = 1;
3767 rowspan = 1;
3733 else
3768 else
3734 rowspan = attrs['rowspan'].to_i;
3769 rowspan = attrs['rowspan'].to_i;
3735 end
3770 end
3736
3771
3737 i = 0;
3772 i = 0;
3738 while true
3773 while true
3739 next_i_distance = checkTableBlockingCellPosition(@table_id, @tr_id, @td_id + i);
3774 next_i_distance = checkTableBlockingCellPosition(@table_id, @tr_id, @td_id + i);
3740 if next_i_distance == 0
3775 if next_i_distance == 0
3741 @t_cells[@table_id][@tr_id].push "i0"=>@td_id + i, "j0"=>@tr_id, "i1"=>(@td_id + i + colspan - 1), "j1"=>@tr_id + rowspan - 1
3776 @t_cells[@table_id][@tr_id].push "i0"=>@td_id + i, "j0"=>@tr_id, "i1"=>(@td_id + i + colspan - 1), "j1"=>@tr_id + rowspan - 1
3742 break;
3777 break;
3743 end
3778 end
3744 i += next_i_distance;
3779 i += next_i_distance;
3745 end
3780 end
3746
3781
3747 @t_columns += colspan;
3782 @t_columns += colspan;
3748 end
3783 end
3749 end
3784 end
3750
3785
3751 #
3786 #
3752 # Calculate closing tags.
3787 # Calculate closing tags.
3753 # @param string :tag tag name (in upcase)
3788 # @param string :tag tag name (in upcase)
3754 # @access private
3789 # @access private
3755 #
3790 #
3756 def closedHTMLTagCalc(tag)
3791 def closedHTMLTagCalc(tag)
3757 #Closing tag
3792 #Closing tag
3758 case (tag)
3793 case (tag)
3759 when 'table'
3794 when 'table'
3760 if @max_table_columns[@table_id] < @t_columns
3795 if @max_table_columns[@table_id] < @t_columns
3761 @max_table_columns[@table_id] = @t_columns;
3796 @max_table_columns[@table_id] = @t_columns;
3762 end
3797 end
3763 @table_id += 1;
3798 @table_id += 1;
3764 @t_cells.push []
3799 @t_cells.push []
3765 end
3800 end
3766 end
3801 end
3767
3802
3768 #
3803 #
3804 # Convert to accessible file path
3805 # @param string :attrname image file name
3806 #
3807 def getImageFilename( attrname )
3808 nil
3809 end
3810
3811 #
3769 # Process opening tags.
3812 # Process opening tags.
3770 # @param string :tag tag name (in upcase)
3813 # @param string :tag tag name (in upcase)
3771 # @param string :attr tag attribute (in upcase)
3814 # @param string :attr tag attribute (in upcase)
3772 # @param int :fill Indicates if the cell background must be painted (1) or transparent (0). Default value: 0.
3815 # @param int :fill Indicates if the cell background must be painted (1) or transparent (0). Default value: 0.
3773 # @access private
3816 # @access private
3774 #
3817 #
3775 def openHTMLTagHandler(tag, attrs, fill=0)
3818 def openHTMLTagHandler(tag, attrs, fill=0)
3776 #Opening tag
3819 #Opening tag
3777 case (tag)
3820 case (tag)
3778 when 'pre'
3821 when 'pre'
3779 @pre_state = true;
3822 @pre_state = true;
3780 @l_margin += 5;
3823 @l_margin += 5;
3781 @r_margin += 5;
3824 @r_margin += 5;
3782 @x += 5;
3825 @x += 5;
3783
3826
3784 when 'table'
3827 when 'table'
3785 if @default_table_columns < @max_table_columns[@table_id]
3828 if @default_table_columns < @max_table_columns[@table_id]
3786 @table_columns = @max_table_columns[@table_id];
3829 @table_columns = @max_table_columns[@table_id];
3787 else
3830 else
3788 @table_columns = @default_table_columns;
3831 @table_columns = @default_table_columns;
3789 end
3832 end
3790 @l_margin += 5;
3833 @l_margin += 5;
3791 @r_margin += 5;
3834 @r_margin += 5;
3792 @x += 5;
3835 @x += 5;
3793
3836
3794 if attrs['border'].nil? or attrs['border'] == ''
3837 if attrs['border'].nil? or attrs['border'] == ''
3795 @tableborder = 0;
3838 @tableborder = 0;
3796 else
3839 else
3797 @tableborder = attrs['border'];
3840 @tableborder = attrs['border'];
3798 end
3841 end
3799 @tr_id = -1;
3842 @tr_id = -1;
3800 @max_td_page[0] = @page;
3843 @max_td_page[0] = @page;
3801 @max_td_y[0] = @y;
3844 @max_td_y[0] = @y;
3802
3845
3803 when 'tr', 'td', 'th'
3846 when 'tr', 'td', 'th'
3804 if tag == 'th'
3847 if tag == 'th'
3805 SetStyle('b', true);
3848 SetStyle('b', true);
3806 @tdalign = "C";
3849 @tdalign = "C";
3807 end
3850 end
3808 if ((!attrs['width'].nil?) and (attrs['width'] != ''))
3851 if ((!attrs['width'].nil?) and (attrs['width'] != ''))
3809 @tdwidth = (attrs['width'].to_i/4);
3852 @tdwidth = (attrs['width'].to_i/4);
3810 else
3853 else
3811 @tdwidth = ((@w - @l_margin - @r_margin) / @table_columns);
3854 @tdwidth = ((@w - @l_margin - @r_margin) / @table_columns);
3812 end
3855 end
3813
3856
3814 if tag == 'tr'
3857 if tag == 'tr'
3815 @tr_id += 1;
3858 @tr_id += 1;
3816 @td_id = -1;
3859 @td_id = -1;
3817 else
3860 else
3818 @td_id += 1;
3861 @td_id += 1;
3819 @x = @l_margin + @tdwidth * @t_cells[@table_id][@tr_id][@td_id]['i0'];
3862 @x = @l_margin + @tdwidth * @t_cells[@table_id][@tr_id][@td_id]['i0'];
3820 end
3863 end
3821
3864
3822 if attrs['colspan'].nil? or attrs['border'] == ''
3865 if attrs['colspan'].nil? or attrs['border'] == ''
3823 @colspan = 1;
3866 @colspan = 1;
3824 else
3867 else
3825 @colspan = attrs['colspan'].to_i;
3868 @colspan = attrs['colspan'].to_i;
3826 end
3869 end
3827 @tdwidth *= @colspan;
3870 @tdwidth *= @colspan;
3828 if ((!attrs['height'].nil?) and (attrs['height'] != ''))
3871 if ((!attrs['height'].nil?) and (attrs['height'] != ''))
3829 @tdheight=(attrs['height'].to_i / @k);
3872 @tdheight=(attrs['height'].to_i / @k);
3830 else
3873 else
3831 @tdheight = @lasth;
3874 @tdheight = @lasth;
3832 end
3875 end
3833 if ((!attrs['align'].nil?) and (attrs['align'] != ''))
3876 if ((!attrs['align'].nil?) and (attrs['align'] != ''))
3834 case (attrs['align'])
3877 case (attrs['align'])
3835 when 'center'
3878 when 'center'
3836 @tdalign = "C";
3879 @tdalign = "C";
3837 when 'right'
3880 when 'right'
3838 @tdalign = "R";
3881 @tdalign = "R";
3839 when 'left'
3882 when 'left'
3840 @tdalign = "L";
3883 @tdalign = "L";
3841 end
3884 end
3842 end
3885 end
3843 if ((!attrs['bgcolor'].nil?) and (attrs['bgcolor'] != ''))
3886 if ((!attrs['bgcolor'].nil?) and (attrs['bgcolor'] != ''))
3844 coul = convertColorHexToDec(attrs['bgcolor']);
3887 coul = convertColorHexToDec(attrs['bgcolor']);
3845 SetFillColor(coul['R'], coul['G'], coul['B']);
3888 SetFillColor(coul['R'], coul['G'], coul['B']);
3846 @tdfill=1;
3889 @tdfill=1;
3847 end
3890 end
3848 @tdbegin=true;
3891 @tdbegin=true;
3849
3892
3850 when 'hr'
3893 when 'hr'
3851 margin = 1;
3894 margin = 1;
3852 if ((!attrs['width'].nil?) and (attrs['width'] != ''))
3895 if ((!attrs['width'].nil?) and (attrs['width'] != ''))
3853 hrWidth = attrs['width'];
3896 hrWidth = attrs['width'];
3854 else
3897 else
3855 hrWidth = @w - @l_margin - @r_margin - margin;
3898 hrWidth = @w - @l_margin - @r_margin - margin;
3856 end
3899 end
3857 SetLineWidth(0.2);
3900 SetLineWidth(0.2);
3858 Line(@x + margin, @y, @x + hrWidth, @y);
3901 Line(@x + margin, @y, @x + hrWidth, @y);
3859 Ln();
3902 Ln();
3860
3903
3861 when 'strong'
3904 when 'strong'
3862 SetStyle('b', true);
3905 SetStyle('b', true);
3863
3906
3864 when 'em'
3907 when 'em'
3865 SetStyle('i', true);
3908 SetStyle('i', true);
3866
3909
3867 when 'ins'
3910 when 'ins'
3868 SetStyle('u', true);
3911 SetStyle('u', true);
3869
3912
3870 when 'del'
3913 when 'del'
3871 SetStyle('d', true);
3914 SetStyle('d', true);
3872
3915
3873 when 'b', 'i', 'u'
3916 when 'b', 'i', 'u'
3874 SetStyle(tag, true);
3917 SetStyle(tag, true);
3875
3918
3876 when 'a'
3919 when 'a'
3877 @href = attrs['href'];
3920 @href = attrs['href'];
3878
3921
3879 when 'img'
3922 when 'img'
3880 if (!attrs['src'].nil?)
3923 if (!attrs['src'].nil?)
3881 Write(@lasth, '!' + attrs['src'] + '!', '', fill);
3924 # Only generates image include a pdf if RMagick is avalaible
3882 =begin Comment out. Because not implement image output yet.
3925 unless Object.const_defined?(:Magick)
3883 # replace relative path with real server path
3926 Write(@lasth, attrs['src'], '', fill);
3884 attrs['src'] = attrs['src'].gsub(@@k_path_url_cache, @@k_path_cache);
3927 return
3928 end
3929 file = getImageFilename(attrs['src'])
3930 if (file.nil?)
3931 Write(@lasth, attrs['src'], '', fill);
3932 return
3933 end
3934
3885 if (attrs['width'].nil?)
3935 if (attrs['width'].nil?)
3886 attrs['width'] = 0;
3936 attrs['width'] = 0;
3887 end
3937 end
3888 if (attrs['height'].nil?)
3938 if (attrs['height'].nil?)
3889 attrs['height'] = 0;
3939 attrs['height'] = 0;
3890 end
3940 end
3891
3941
3892 Image(attrs['src'], GetX(),GetY(), pixelsToMillimeters(attrs['width']), pixelsToMillimeters(attrs['height']));
3942 begin
3893 #SetX(@img_rb_x);
3943 Image(file, GetX(),GetY(), pixelsToMillimeters(attrs['width']), pixelsToMillimeters(attrs['height']));
3894 SetY(@img_rb_y);
3944 #SetX(@img_rb_x);
3895 =end
3945 SetY(@img_rb_y);
3946 rescue => err
3947 logger.error "pdf: Image: error: #{err.message}"
3948 Write(@lasth, attrs['src'], '', fill);
3949 if File.file?( @@k_path_cache + File::basename(file))
3950 File.delete( @@k_path_cache + File::basename(file))
3951 end
3952 end
3896 end
3953 end
3897
3954
3898 when 'ul', 'ol'
3955 when 'ul', 'ol'
3899 if @li_count == 0
3956 if @li_count == 0
3900 Ln() if @prevquote_count == @quote_count; # insert Ln for keeping quote lines
3957 Ln() if @prevquote_count == @quote_count; # insert Ln for keeping quote lines
3901 @prevquote_count = @quote_count;
3958 @prevquote_count = @quote_count;
3902 end
3959 end
3903 if @li_state == true
3960 if @li_state == true
3904 Ln();
3961 Ln();
3905 @li_state = false;
3962 @li_state = false;
3906 end
3963 end
3907 if tag == 'ul'
3964 if tag == 'ul'
3908 @list_ordered[@li_count] = false;
3965 @list_ordered[@li_count] = false;
3909 else
3966 else
3910 @list_ordered[@li_count] = true;
3967 @list_ordered[@li_count] = true;
3911 end
3968 end
3912 @list_count[@li_count] = 0;
3969 @list_count[@li_count] = 0;
3913 @li_count += 1
3970 @li_count += 1
3914
3971
3915 when 'li'
3972 when 'li'
3916 Ln() if @li_state == true
3973 Ln() if @li_state == true
3917 if (@list_ordered[@li_count - 1])
3974 if (@list_ordered[@li_count - 1])
3918 @list_count[@li_count - 1] += 1;
3975 @list_count[@li_count - 1] += 1;
3919 @li_spacer = " " * @li_count + (@list_count[@li_count - 1]).to_s + ". ";
3976 @li_spacer = " " * @li_count + (@list_count[@li_count - 1]).to_s + ". ";
3920 else
3977 else
3921 #unordered list simbol
3978 #unordered list simbol
3922 @li_spacer = " " * @li_count + "- ";
3979 @li_spacer = " " * @li_count + "- ";
3923 end
3980 end
3924 Write(@lasth, @spacer + @li_spacer, '', fill);
3981 Write(@lasth, @spacer + @li_spacer, '', fill);
3925 @li_state = true;
3982 @li_state = true;
3926
3983
3927 when 'blockquote'
3984 when 'blockquote'
3928 if (@quote_count == 0)
3985 if (@quote_count == 0)
3929 SetStyle('i', true);
3986 SetStyle('i', true);
3930 @l_margin += 5;
3987 @l_margin += 5;
3931 else
3988 else
3932 @l_margin += 5 / 2;
3989 @l_margin += 5 / 2;
3933 end
3990 end
3934 @x = @l_margin;
3991 @x = @l_margin;
3935 @quote_top[@quote_count] = @y;
3992 @quote_top[@quote_count] = @y;
3936 @quote_page[@quote_count] = @page;
3993 @quote_page[@quote_count] = @page;
3937 @quote_count += 1
3994 @quote_count += 1
3938 when 'br'
3995 when 'br'
3939 Ln();
3996 Ln();
3940
3997
3941 if (@li_spacer.length > 0)
3998 if (@li_spacer.length > 0)
3942 @x += GetStringWidth(@li_spacer);
3999 @x += GetStringWidth(@li_spacer);
3943 end
4000 end
3944
4001
3945 when 'p'
4002 when 'p'
3946 Ln();
4003 Ln();
3947 0.upto(@quote_count - 1) do |i|
4004 0.upto(@quote_count - 1) do |i|
3948 if @quote_page[i] == @page;
4005 if @quote_page[i] == @page;
3949 if @quote_top[i] == @y - @lasth; # fix start line
4006 if @quote_top[i] == @y - @lasth; # fix start line
3950 @quote_top[i] = @y;
4007 @quote_top[i] = @y;
3951 end
4008 end
3952 else
4009 else
3953 if @quote_page[i] == @page - 1;
4010 if @quote_page[i] == @page - 1;
3954 @quote_page[i] = @page; # fix start line
4011 @quote_page[i] = @page; # fix start line
3955 @quote_top[i] = @t_margin;
4012 @quote_top[i] = @t_margin;
3956 end
4013 end
3957 end
4014 end
3958 end
4015 end
3959
4016
3960 when 'sup'
4017 when 'sup'
3961 currentfont_size = @font_size;
4018 currentfont_size = @font_size;
3962 @tempfontsize = @font_size_pt;
4019 @tempfontsize = @font_size_pt;
3963 SetFontSize(@font_size_pt * @@k_small_ratio);
4020 SetFontSize(@font_size_pt * @@k_small_ratio);
3964 SetXY(GetX(), GetY() - ((currentfont_size - @font_size)*(@@k_small_ratio)));
4021 SetXY(GetX(), GetY() - ((currentfont_size - @font_size)*(@@k_small_ratio)));
3965
4022
3966 when 'sub'
4023 when 'sub'
3967 currentfont_size = @font_size;
4024 currentfont_size = @font_size;
3968 @tempfontsize = @font_size_pt;
4025 @tempfontsize = @font_size_pt;
3969 SetFontSize(@font_size_pt * @@k_small_ratio);
4026 SetFontSize(@font_size_pt * @@k_small_ratio);
3970 SetXY(GetX(), GetY() + ((currentfont_size - @font_size)*(@@k_small_ratio)));
4027 SetXY(GetX(), GetY() + ((currentfont_size - @font_size)*(@@k_small_ratio)));
3971
4028
3972 when 'small'
4029 when 'small'
3973 currentfont_size = @font_size;
4030 currentfont_size = @font_size;
3974 @tempfontsize = @font_size_pt;
4031 @tempfontsize = @font_size_pt;
3975 SetFontSize(@font_size_pt * @@k_small_ratio);
4032 SetFontSize(@font_size_pt * @@k_small_ratio);
3976 SetXY(GetX(), GetY() + ((currentfont_size - @font_size)/3));
4033 SetXY(GetX(), GetY() + ((currentfont_size - @font_size)/3));
3977
4034
3978 when 'font'
4035 when 'font'
3979 if (!attrs['color'].nil? and attrs['color']!='')
4036 if (!attrs['color'].nil? and attrs['color']!='')
3980 coul = convertColorHexToDec(attrs['color']);
4037 coul = convertColorHexToDec(attrs['color']);
3981 SetTextColor(coul['R'], coul['G'], coul['B']);
4038 SetTextColor(coul['R'], coul['G'], coul['B']);
3982 @issetcolor=true;
4039 @issetcolor=true;
3983 end
4040 end
3984 if (!attrs['face'].nil? and @fontlist.include?(attrs['face'].downcase))
4041 if (!attrs['face'].nil? and @fontlist.include?(attrs['face'].downcase))
3985 SetFont(attrs['face'].downcase);
4042 SetFont(attrs['face'].downcase);
3986 @issetfont=true;
4043 @issetfont=true;
3987 end
4044 end
3988 if (!attrs['size'].nil?)
4045 if (!attrs['size'].nil?)
3989 headsize = attrs['size'].to_i;
4046 headsize = attrs['size'].to_i;
3990 else
4047 else
3991 headsize = 0;
4048 headsize = 0;
3992 end
4049 end
3993 currentfont_size = @font_size;
4050 currentfont_size = @font_size;
3994 @tempfontsize = @font_size_pt;
4051 @tempfontsize = @font_size_pt;
3995 SetFontSize(@font_size_pt + headsize);
4052 SetFontSize(@font_size_pt + headsize);
3996 @lasth = @font_size * @@k_cell_height_ratio;
4053 @lasth = @font_size * @@k_cell_height_ratio;
3997
4054
3998 when 'h1', 'h2', 'h3', 'h4', 'h5', 'h6'
4055 when 'h1', 'h2', 'h3', 'h4', 'h5', 'h6'
3999 Ln();
4056 Ln();
4000 headsize = (4 - tag[1,1].to_f) * 2
4057 headsize = (4 - tag[1,1].to_f) * 2
4001 @tempfontsize = @font_size_pt;
4058 @tempfontsize = @font_size_pt;
4002 SetFontSize(@font_size_pt + headsize);
4059 SetFontSize(@font_size_pt + headsize);
4003 SetStyle('b', true);
4060 SetStyle('b', true);
4004 @lasth = @font_size * @@k_cell_height_ratio;
4061 @lasth = @font_size * @@k_cell_height_ratio;
4005
4062
4006 end
4063 end
4007 end
4064 end
4008
4065
4009 #
4066 #
4010 # Process closing tags.
4067 # Process closing tags.
4011 # @param string :tag tag name (in upcase)
4068 # @param string :tag tag name (in upcase)
4012 # @access private
4069 # @access private
4013 #
4070 #
4014 def closedHTMLTagHandler(tag)
4071 def closedHTMLTagHandler(tag)
4015 #Closing tag
4072 #Closing tag
4016 case (tag)
4073 case (tag)
4017 when 'pre'
4074 when 'pre'
4018 @pre_state = false;
4075 @pre_state = false;
4019 @l_margin -= 5;
4076 @l_margin -= 5;
4020 @r_margin -= 5;
4077 @r_margin -= 5;
4021 @x = @l_margin;
4078 @x = @l_margin;
4022 Ln();
4079 Ln();
4023
4080
4024 when 'td','th'
4081 when 'td','th'
4025 @tdbegin = false;
4082 @tdbegin = false;
4026 @tdwidth = 0;
4083 @tdwidth = 0;
4027 @tdheight = 0;
4084 @tdheight = 0;
4028 @tdalign = "L";
4085 @tdalign = "L";
4029 SetStyle('b', false);
4086 SetStyle('b', false);
4030 @tdfill = 0;
4087 @tdfill = 0;
4031 SetFillColor(@prevfill_color[0], @prevfill_color[1], @prevfill_color[2]);
4088 SetFillColor(@prevfill_color[0], @prevfill_color[1], @prevfill_color[2]);
4032
4089
4033 when 'tr'
4090 when 'tr'
4034 @y = @max_td_y[@tr_id + 1];
4091 @y = @max_td_y[@tr_id + 1];
4035 @x = @l_margin;
4092 @x = @l_margin;
4036 @page = @max_td_page[@tr_id + 1];
4093 @page = @max_td_page[@tr_id + 1];
4037
4094
4038 when 'table'
4095 when 'table'
4039 # Write Table Line
4096 # Write Table Line
4040 width = (@w - @l_margin - @r_margin) / @table_columns;
4097 width = (@w - @l_margin - @r_margin) / @table_columns;
4041 0.upto(@t_cells[@table_id].size - 1) do |j|
4098 0.upto(@t_cells[@table_id].size - 1) do |j|
4042 0.upto(@t_cells[@table_id][j].size - 1) do |i|
4099 0.upto(@t_cells[@table_id][j].size - 1) do |i|
4043 @page = @max_td_page[j]
4100 @page = @max_td_page[j]
4044 i0=@t_cells[@table_id][j][i]['i0'];
4101 i0=@t_cells[@table_id][j][i]['i0'];
4045 j0=@t_cells[@table_id][j][i]['j0'];
4102 j0=@t_cells[@table_id][j][i]['j0'];
4046 i1=@t_cells[@table_id][j][i]['i1'];
4103 i1=@t_cells[@table_id][j][i]['i1'];
4047 j1=@t_cells[@table_id][j][i]['j1'];
4104 j1=@t_cells[@table_id][j][i]['j1'];
4048
4105
4049 Line(@l_margin + width * i0, @max_td_y[j0], @l_margin + width * (i1+1), @max_td_y[j0]) # top
4106 Line(@l_margin + width * i0, @max_td_y[j0], @l_margin + width * (i1+1), @max_td_y[j0]) # top
4050 if ( @page == @max_td_page[j1 + 1])
4107 if ( @page == @max_td_page[j1 + 1])
4051 Line(@l_margin + width * i0, @max_td_y[j0], @l_margin + width * i0, @max_td_y[j1+1]) # left
4108 Line(@l_margin + width * i0, @max_td_y[j0], @l_margin + width * i0, @max_td_y[j1+1]) # left
4052 Line(@l_margin + width * (i1+1), @max_td_y[j0], @l_margin + width * (i1+1), @max_td_y[j1+1]) # right
4109 Line(@l_margin + width * (i1+1), @max_td_y[j0], @l_margin + width * (i1+1), @max_td_y[j1+1]) # right
4053 else
4110 else
4054 Line(@l_margin + width * i0, @max_td_y[j0], @l_margin + width * i0, @page_break_trigger) # left
4111 Line(@l_margin + width * i0, @max_td_y[j0], @l_margin + width * i0, @page_break_trigger) # left
4055 Line(@l_margin + width * (i1+1), @max_td_y[j0], @l_margin + width * (i1+1), @page_break_trigger) # right
4112 Line(@l_margin + width * (i1+1), @max_td_y[j0], @l_margin + width * (i1+1), @page_break_trigger) # right
4056 @page += 1;
4113 @page += 1;
4057 while @page < @max_td_page[j1 + 1]
4114 while @page < @max_td_page[j1 + 1]
4058 Line(@l_margin + width * i0, @t_margin, @l_margin + width * i0, @page_break_trigger) # left
4115 Line(@l_margin + width * i0, @t_margin, @l_margin + width * i0, @page_break_trigger) # left
4059 Line(@l_margin + width * (i1+1), @t_margin, @l_margin + width * (i1+1), @page_break_trigger) # right
4116 Line(@l_margin + width * (i1+1), @t_margin, @l_margin + width * (i1+1), @page_break_trigger) # right
4060 @page += 1;
4117 @page += 1;
4061 end
4118 end
4062 Line(@l_margin + width * i0, @t_margin, @l_margin + width * i0, @max_td_y[j1+1]) # left
4119 Line(@l_margin + width * i0, @t_margin, @l_margin + width * i0, @max_td_y[j1+1]) # left
4063 Line(@l_margin + width * (i1+1), @t_margin, @l_margin + width * (i1+1), @max_td_y[j1+1]) # right
4120 Line(@l_margin + width * (i1+1), @t_margin, @l_margin + width * (i1+1), @max_td_y[j1+1]) # right
4064 end
4121 end
4065 Line(@l_margin + width * i0, @max_td_y[j1+1], @l_margin + width * (i1+1), @max_td_y[j1+1]) # bottom
4122 Line(@l_margin + width * i0, @max_td_y[j1+1], @l_margin + width * (i1+1), @max_td_y[j1+1]) # bottom
4066 end
4123 end
4067 end
4124 end
4068
4125
4069 @l_margin -= 5;
4126 @l_margin -= 5;
4070 @r_margin -= 5;
4127 @r_margin -= 5;
4071 @tableborder=0;
4128 @tableborder=0;
4072 Ln();
4129 Ln();
4073 @table_id += 1;
4130 @table_id += 1;
4074
4131
4075 when 'strong'
4132 when 'strong'
4076 SetStyle('b', false);
4133 SetStyle('b', false);
4077
4134
4078 when 'em'
4135 when 'em'
4079 SetStyle('i', false);
4136 SetStyle('i', false);
4080
4137
4081 when 'ins'
4138 when 'ins'
4082 SetStyle('u', false);
4139 SetStyle('u', false);
4083
4140
4084 when 'del'
4141 when 'del'
4085 SetStyle('d', false);
4142 SetStyle('d', false);
4086
4143
4087 when 'b', 'i', 'u'
4144 when 'b', 'i', 'u'
4088 SetStyle(tag, false);
4145 SetStyle(tag, false);
4089
4146
4090 when 'a'
4147 when 'a'
4091 @href = nil;
4148 @href = nil;
4092
4149
4093 when 'p'
4150 when 'p'
4094 Ln();
4151 Ln();
4095
4152
4096 when 'sup'
4153 when 'sup'
4097 currentfont_size = @font_size;
4154 currentfont_size = @font_size;
4098 SetFontSize(@tempfontsize);
4155 SetFontSize(@tempfontsize);
4099 @tempfontsize = @font_size_pt;
4156 @tempfontsize = @font_size_pt;
4100 SetXY(GetX(), GetY() - ((currentfont_size - @font_size)*(@@k_small_ratio)));
4157 SetXY(GetX(), GetY() - ((currentfont_size - @font_size)*(@@k_small_ratio)));
4101
4158
4102 when 'sub'
4159 when 'sub'
4103 currentfont_size = @font_size;
4160 currentfont_size = @font_size;
4104 SetFontSize(@tempfontsize);
4161 SetFontSize(@tempfontsize);
4105 @tempfontsize = @font_size_pt;
4162 @tempfontsize = @font_size_pt;
4106 SetXY(GetX(), GetY() + ((currentfont_size - @font_size)*(@@k_small_ratio)));
4163 SetXY(GetX(), GetY() + ((currentfont_size - @font_size)*(@@k_small_ratio)));
4107
4164
4108 when 'small'
4165 when 'small'
4109 currentfont_size = @font_size;
4166 currentfont_size = @font_size;
4110 SetFontSize(@tempfontsize);
4167 SetFontSize(@tempfontsize);
4111 @tempfontsize = @font_size_pt;
4168 @tempfontsize = @font_size_pt;
4112 SetXY(GetX(), GetY() - ((@font_size - currentfont_size)/3));
4169 SetXY(GetX(), GetY() - ((@font_size - currentfont_size)/3));
4113
4170
4114 when 'font'
4171 when 'font'
4115 if (@issetcolor == true)
4172 if (@issetcolor == true)
4116 SetTextColor(@prevtext_color[0], @prevtext_color[1], @prevtext_color[2]);
4173 SetTextColor(@prevtext_color[0], @prevtext_color[1], @prevtext_color[2]);
4117 end
4174 end
4118 if (@issetfont)
4175 if (@issetfont)
4119 @font_family = @prevfont_family;
4176 @font_family = @prevfont_family;
4120 @font_style = @prevfont_style;
4177 @font_style = @prevfont_style;
4121 SetFont(@font_family);
4178 SetFont(@font_family);
4122 @issetfont = false;
4179 @issetfont = false;
4123 end
4180 end
4124 currentfont_size = @font_size;
4181 currentfont_size = @font_size;
4125 SetFontSize(@tempfontsize);
4182 SetFontSize(@tempfontsize);
4126 @tempfontsize = @font_size_pt;
4183 @tempfontsize = @font_size_pt;
4127 #@text_color = @prevtext_color;
4184 #@text_color = @prevtext_color;
4128 @lasth = @font_size * @@k_cell_height_ratio;
4185 @lasth = @font_size * @@k_cell_height_ratio;
4129
4186
4130 when 'blockquote'
4187 when 'blockquote'
4131 @quote_count -= 1
4188 @quote_count -= 1
4132 if (@quote_page[@quote_count] == @page)
4189 if (@quote_page[@quote_count] == @page)
4133 Line(@l_margin - 1, @quote_top[@quote_count], @l_margin - 1, @y) # quoto line
4190 Line(@l_margin - 1, @quote_top[@quote_count], @l_margin - 1, @y) # quoto line
4134 else
4191 else
4135 cur_page = @page;
4192 cur_page = @page;
4136 cur_y = @y;
4193 cur_y = @y;
4137 @page = @quote_page[@quote_count];
4194 @page = @quote_page[@quote_count];
4138 if (@quote_top[@quote_count] < @page_break_trigger)
4195 if (@quote_top[@quote_count] < @page_break_trigger)
4139 Line(@l_margin - 1, @quote_top[@quote_count], @l_margin - 1, @page_break_trigger) # quoto line
4196 Line(@l_margin - 1, @quote_top[@quote_count], @l_margin - 1, @page_break_trigger) # quoto line
4140 end
4197 end
4141 @page += 1;
4198 @page += 1;
4142 while @page < cur_page
4199 while @page < cur_page
4143 Line(@l_margin - 1, @t_margin, @l_margin - 1, @page_break_trigger) # quoto line
4200 Line(@l_margin - 1, @t_margin, @l_margin - 1, @page_break_trigger) # quoto line
4144 @page += 1;
4201 @page += 1;
4145 end
4202 end
4146 @y = cur_y;
4203 @y = cur_y;
4147 Line(@l_margin - 1, @t_margin, @l_margin - 1, @y) # quoto line
4204 Line(@l_margin - 1, @t_margin, @l_margin - 1, @y) # quoto line
4148 end
4205 end
4149 if (@quote_count <= 0)
4206 if (@quote_count <= 0)
4150 SetStyle('i', false);
4207 SetStyle('i', false);
4151 @l_margin -= 5;
4208 @l_margin -= 5;
4152 else
4209 else
4153 @l_margin -= 5 / 2;
4210 @l_margin -= 5 / 2;
4154 end
4211 end
4155 @x = @l_margin;
4212 @x = @l_margin;
4156 Ln() if @quote_count == 0
4213 Ln() if @quote_count == 0
4157
4214
4158 when 'ul', 'ol'
4215 when 'ul', 'ol'
4159 @li_count -= 1
4216 @li_count -= 1
4160 if @li_state == true
4217 if @li_state == true
4161 Ln();
4218 Ln();
4162 @li_state = false;
4219 @li_state = false;
4163 end
4220 end
4164
4221
4165 when 'li'
4222 when 'li'
4166 @li_spacer = "";
4223 @li_spacer = "";
4167 if @li_state == true
4224 if @li_state == true
4168 Ln();
4225 Ln();
4169 @li_state = false;
4226 @li_state = false;
4170 end
4227 end
4171
4228
4172 when 'h1', 'h2', 'h3', 'h4', 'h5', 'h6'
4229 when 'h1', 'h2', 'h3', 'h4', 'h5', 'h6'
4173 SetFontSize(@tempfontsize);
4230 SetFontSize(@tempfontsize);
4174 @tempfontsize = @font_size_pt;
4231 @tempfontsize = @font_size_pt;
4175 SetStyle('b', false);
4232 SetStyle('b', false);
4176 Ln();
4233 Ln();
4177 @lasth = @font_size * @@k_cell_height_ratio;
4234 @lasth = @font_size * @@k_cell_height_ratio;
4178
4235
4179 if tag == 'h1' or tag == 'h2' or tag == 'h3' or tag == 'h4'
4236 if tag == 'h1' or tag == 'h2' or tag == 'h3' or tag == 'h4'
4180 margin = 1;
4237 margin = 1;
4181 hrWidth = @w - @l_margin - @r_margin - margin;
4238 hrWidth = @w - @l_margin - @r_margin - margin;
4182 if tag == 'h1' or tag == 'h2'
4239 if tag == 'h1' or tag == 'h2'
4183 SetLineWidth(0.2);
4240 SetLineWidth(0.2);
4184 else
4241 else
4185 SetLineWidth(0.1);
4242 SetLineWidth(0.1);
4186 end
4243 end
4187 Line(@x + margin, @y, @x + hrWidth, @y);
4244 Line(@x + margin, @y, @x + hrWidth, @y);
4188 end
4245 end
4189 end
4246 end
4190 end
4247 end
4191
4248
4192 #
4249 #
4193 # Sets font style.
4250 # Sets font style.
4194 # @param string :tag tag name (in lowercase)
4251 # @param string :tag tag name (in lowercase)
4195 # @param boolean :enable
4252 # @param boolean :enable
4196 # @access private
4253 # @access private
4197 #
4254 #
4198 def SetStyle(tag, enable)
4255 def SetStyle(tag, enable)
4199 #Modify style and select corresponding font
4256 #Modify style and select corresponding font
4200 ['b', 'i', 'u', 'd'].each do |s|
4257 ['b', 'i', 'u', 'd'].each do |s|
4201 if tag.downcase == s
4258 if tag.downcase == s
4202 if enable
4259 if enable
4203 @style << s if ! @style.include?(s)
4260 @style << s if ! @style.include?(s)
4204 else
4261 else
4205 @style = @style.gsub(s,'')
4262 @style = @style.gsub(s,'')
4206 end
4263 end
4207 end
4264 end
4208 end
4265 end
4209 SetFont('', @style);
4266 SetFont('', @style);
4210 end
4267 end
4211
4268
4212 #
4269 #
4213 # Output anchor link.
4270 # Output anchor link.
4214 # @param string :url link URL
4271 # @param string :url link URL
4215 # @param string :name link name
4272 # @param string :name link name
4216 # @param int :fill Indicates if the cell background must be painted (1) or transparent (0). Default value: 0.
4273 # @param int :fill Indicates if the cell background must be painted (1) or transparent (0). Default value: 0.
4217 # @access public
4274 # @access public
4218 #
4275 #
4219 def addHtmlLink(url, name, fill=0)
4276 def addHtmlLink(url, name, fill=0)
4220 #Put a hyperlink
4277 #Put a hyperlink
4221 SetTextColor(0, 0, 255);
4278 SetTextColor(0, 0, 255);
4222 SetStyle('u', true);
4279 SetStyle('u', true);
4223 Write(@lasth, name, url, fill);
4280 Write(@lasth, name, url, fill);
4224 SetStyle('u', false);
4281 SetStyle('u', false);
4225 SetTextColor(0);
4282 SetTextColor(0);
4226 end
4283 end
4227
4284
4228 #
4285 #
4229 # Returns an associative array (keys: R,G,B) from
4286 # Returns an associative array (keys: R,G,B) from
4230 # a hex html code (e.g. #3FE5AA).
4287 # a hex html code (e.g. #3FE5AA).
4231 # @param string :color hexadecimal html color [#rrggbb]
4288 # @param string :color hexadecimal html color [#rrggbb]
4232 # @return array
4289 # @return array
4233 # @access private
4290 # @access private
4234 #
4291 #
4235 def convertColorHexToDec(color = "#000000")
4292 def convertColorHexToDec(color = "#000000")
4236 tbl_color = {}
4293 tbl_color = {}
4237 tbl_color['R'] = color[1,2].hex.to_i;
4294 tbl_color['R'] = color[1,2].hex.to_i;
4238 tbl_color['G'] = color[3,2].hex.to_i;
4295 tbl_color['G'] = color[3,2].hex.to_i;
4239 tbl_color['B'] = color[5,2].hex.to_i;
4296 tbl_color['B'] = color[5,2].hex.to_i;
4240 return tbl_color;
4297 return tbl_color;
4241 end
4298 end
4242
4299
4243 #
4300 #
4244 # Converts pixels to millimeters in 72 dpi.
4301 # Converts pixels to millimeters in 72 dpi.
4245 # @param int :px pixels
4302 # @param int :px pixels
4246 # @return float millimeters
4303 # @return float millimeters
4247 # @access private
4304 # @access private
4248 #
4305 #
4249 def pixelsToMillimeters(px)
4306 def pixelsToMillimeters(px)
4250 return px.to_f * 25.4 / 72;
4307 return px.to_f * 25.4 / 72;
4251 end
4308 end
4252
4309
4253 #
4310 #
4254 # Reverse function for htmlentities.
4311 # Reverse function for htmlentities.
4255 # Convert entities in UTF-8.
4312 # Convert entities in UTF-8.
4256 #
4313 #
4257 # @param :text_to_convert Text to convert.
4314 # @param :text_to_convert Text to convert.
4258 # @return string converted
4315 # @return string converted
4259 #
4316 #
4260 def unhtmlentities(string)
4317 def unhtmlentities(string)
4261 if @@decoder.nil?
4318 if @@decoder.nil?
4262 CGI.unescapeHTML(string)
4319 CGI.unescapeHTML(string)
4263 else
4320 else
4264 @@decoder.decode(string)
4321 @@decoder.decode(string)
4265 end
4322 end
4266 end
4323 end
4267
4324
4268 end # END OF CLASS
4325 end # END OF CLASS
4269
4326
4270 #TODO 2007-05-25 (EJM) Level=0 -
4327 #TODO 2007-05-25 (EJM) Level=0 -
4271 #Handle special IE contype request
4328 #Handle special IE contype request
4272 # if (!_SERVER['HTTP_USER_AGENT'].nil? and (_SERVER['HTTP_USER_AGENT']=='contype'))
4329 # if (!_SERVER['HTTP_USER_AGENT'].nil? and (_SERVER['HTTP_USER_AGENT']=='contype'))
4273 # header('Content-Type: application/pdf');
4330 # header('Content-Type: application/pdf');
4274 # exit;
4331 # exit;
4275 # }
4332 # }
General Comments 0
You need to be logged in to leave comments. Login now