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