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