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