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