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