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