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