##// END OF EJS Templates
ruby1.9 compatibility...
Jean-Philippe Lang -
r4482:2c830770cb39
parent child
Show More
@@ -1,1550 +1,1558
1 # Ruby FPDF 1.53d
1 # Ruby FPDF 1.53d
2 # FPDF 1.53 by Olivier Plathey ported to Ruby by Brian Ollenberger
2 # FPDF 1.53 by Olivier Plathey ported to Ruby by Brian Ollenberger
3 # Copyright 2005 Brian Ollenberger
3 # Copyright 2005 Brian Ollenberger
4 # Please retain this entire copyright notice. If you distribute any
4 # Please retain this entire copyright notice. If you distribute any
5 # modifications, place an additional comment here that clearly indicates
5 # modifications, place an additional comment here that clearly indicates
6 # that it was modified. You may (but are not send any useful modifications that you make
6 # that it was modified. You may (but are not send any useful modifications that you make
7 # back to me at http://zeropluszero.com/software/fpdf/
7 # back to me at http://zeropluszero.com/software/fpdf/
8
8
9 # Bug fixes, examples, external fonts, JPEG support, and upgrade to version
9 # Bug fixes, examples, external fonts, JPEG support, and upgrade to version
10 # 1.53 contributed by Kim Shrier.
10 # 1.53 contributed by Kim Shrier.
11 #
11 #
12 # Bookmark support contributed by Sylvain Lafleur.
12 # Bookmark support contributed by Sylvain Lafleur.
13 #
13 #
14 # EPS support contributed by Thiago Jackiw, ported from the PHP version by Valentin Schmidt.
14 # EPS support contributed by Thiago Jackiw, ported from the PHP version by Valentin Schmidt.
15 #
15 #
16 # Bookmarks contributed by Sylvain Lafleur.
16 # Bookmarks contributed by Sylvain Lafleur.
17 #
17 #
18 # 1.53 contributed by Ed Moss
18 # 1.53 contributed by Ed Moss
19 # Handle '\n' at the beginning of a string
19 # Handle '\n' at the beginning of a string
20 # Bookmarks contributed by Sylvain Lafleur.
20 # Bookmarks contributed by Sylvain Lafleur.
21
21
22 require 'date'
22 require 'date'
23 require 'zlib'
23 require 'zlib'
24
24
25 class FPDF
25 class FPDF
26 FPDF_VERSION = '1.53d'
26 FPDF_VERSION = '1.53d'
27
27
28 Charwidths = {
28 Charwidths = {
29 'courier'=>[600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600],
29 'courier'=>[600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600],
30
30
31 'courierB'=>[600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600],
31 'courierB'=>[600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600],
32
32
33 'courierI'=>[600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600],
33 'courierI'=>[600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600],
34
34
35 'courierBI'=>[600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600],
35 'courierBI'=>[600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600],
36
36
37 'helvetica'=>[278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 355, 556, 556, 889, 667, 191, 333, 333, 389, 584, 278, 333, 278, 278, 556, 556, 556, 556, 556, 556, 556, 556, 556, 556, 278, 278, 584, 584, 584, 556, 1015, 667, 667, 722, 722, 667, 611, 778, 722, 278, 500, 667, 556, 833, 722, 778, 667, 778, 722, 667, 611, 722, 667, 944, 667, 667, 611, 278, 278, 278, 469, 556, 333, 556, 556, 500, 556, 556, 278, 556, 556, 222, 222, 500, 222, 833, 556, 556, 556, 556, 333, 500, 278, 556, 500, 722, 500, 500, 500, 334, 260, 334, 584, 350, 556, 350, 222, 556, 333, 1000, 556, 556, 333, 1000, 667, 333, 1000, 350, 611, 350, 350, 222, 222, 333, 333, 350, 556, 1000, 333, 1000, 500, 333, 944, 350, 500, 667, 278, 333, 556, 556, 556, 556, 260, 556, 333, 737, 370, 556, 584, 333, 737, 333, 400, 584, 333, 333, 333, 556, 537, 278, 333, 333, 365, 556, 834, 834, 834, 611, 667, 667, 667, 667, 667, 667, 1000, 722, 667, 667, 667, 667, 278, 278, 278, 278, 722, 722, 778, 778, 778, 778, 778, 584, 778, 722, 722, 722, 722, 667, 667, 611, 556, 556, 556, 556, 556, 556, 889, 500, 556, 556, 556, 556, 278, 278, 278, 278, 556, 556, 556, 556, 556, 556, 556, 584, 611, 556, 556, 556, 556, 500, 556, 500],
37 'helvetica'=>[278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 355, 556, 556, 889, 667, 191, 333, 333, 389, 584, 278, 333, 278, 278, 556, 556, 556, 556, 556, 556, 556, 556, 556, 556, 278, 278, 584, 584, 584, 556, 1015, 667, 667, 722, 722, 667, 611, 778, 722, 278, 500, 667, 556, 833, 722, 778, 667, 778, 722, 667, 611, 722, 667, 944, 667, 667, 611, 278, 278, 278, 469, 556, 333, 556, 556, 500, 556, 556, 278, 556, 556, 222, 222, 500, 222, 833, 556, 556, 556, 556, 333, 500, 278, 556, 500, 722, 500, 500, 500, 334, 260, 334, 584, 350, 556, 350, 222, 556, 333, 1000, 556, 556, 333, 1000, 667, 333, 1000, 350, 611, 350, 350, 222, 222, 333, 333, 350, 556, 1000, 333, 1000, 500, 333, 944, 350, 500, 667, 278, 333, 556, 556, 556, 556, 260, 556, 333, 737, 370, 556, 584, 333, 737, 333, 400, 584, 333, 333, 333, 556, 537, 278, 333, 333, 365, 556, 834, 834, 834, 611, 667, 667, 667, 667, 667, 667, 1000, 722, 667, 667, 667, 667, 278, 278, 278, 278, 722, 722, 778, 778, 778, 778, 778, 584, 778, 722, 722, 722, 722, 667, 667, 611, 556, 556, 556, 556, 556, 556, 889, 500, 556, 556, 556, 556, 278, 278, 278, 278, 556, 556, 556, 556, 556, 556, 556, 584, 611, 556, 556, 556, 556, 500, 556, 500],
38
38
39 'helveticaB'=>[278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 333, 474, 556, 556, 889, 722, 238, 333, 333, 389, 584, 278, 333, 278, 278, 556, 556, 556, 556, 556, 556, 556, 556, 556, 556, 333, 333, 584, 584, 584, 611, 975, 722, 722, 722, 722, 667, 611, 778, 722, 278, 556, 722, 611, 833, 722, 778, 667, 778, 722, 667, 611, 722, 667, 944, 667, 667, 611, 333, 278, 333, 584, 556, 333, 556, 611, 556, 611, 556, 333, 611, 611, 278, 278, 556, 278, 889, 611, 611, 611, 611, 389, 556, 333, 611, 556, 778, 556, 556, 500, 389, 280, 389, 584, 350, 556, 350, 278, 556, 500, 1000, 556, 556, 333, 1000, 667, 333, 1000, 350, 611, 350, 350, 278, 278, 500, 500, 350, 556, 1000, 333, 1000, 556, 333, 944, 350, 500, 667, 278, 333, 556, 556, 556, 556, 280, 556, 333, 737, 370, 556, 584, 333, 737, 333, 400, 584, 333, 333, 333, 611, 556, 278, 333, 333, 365, 556, 834, 834, 834, 611, 722, 722, 722, 722, 722, 722, 1000, 722, 667, 667, 667, 667, 278, 278, 278, 278, 722, 722, 778, 778, 778, 778, 778, 584, 778, 722, 722, 722, 722, 667, 667, 611, 556, 556, 556, 556, 556, 556, 889, 556, 556, 556, 556, 556, 278, 278, 278, 278, 611, 611, 611, 611, 611, 611, 611, 584, 611, 611, 611, 611, 611, 556, 611, 556],
39 'helveticaB'=>[278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 333, 474, 556, 556, 889, 722, 238, 333, 333, 389, 584, 278, 333, 278, 278, 556, 556, 556, 556, 556, 556, 556, 556, 556, 556, 333, 333, 584, 584, 584, 611, 975, 722, 722, 722, 722, 667, 611, 778, 722, 278, 556, 722, 611, 833, 722, 778, 667, 778, 722, 667, 611, 722, 667, 944, 667, 667, 611, 333, 278, 333, 584, 556, 333, 556, 611, 556, 611, 556, 333, 611, 611, 278, 278, 556, 278, 889, 611, 611, 611, 611, 389, 556, 333, 611, 556, 778, 556, 556, 500, 389, 280, 389, 584, 350, 556, 350, 278, 556, 500, 1000, 556, 556, 333, 1000, 667, 333, 1000, 350, 611, 350, 350, 278, 278, 500, 500, 350, 556, 1000, 333, 1000, 556, 333, 944, 350, 500, 667, 278, 333, 556, 556, 556, 556, 280, 556, 333, 737, 370, 556, 584, 333, 737, 333, 400, 584, 333, 333, 333, 611, 556, 278, 333, 333, 365, 556, 834, 834, 834, 611, 722, 722, 722, 722, 722, 722, 1000, 722, 667, 667, 667, 667, 278, 278, 278, 278, 722, 722, 778, 778, 778, 778, 778, 584, 778, 722, 722, 722, 722, 667, 667, 611, 556, 556, 556, 556, 556, 556, 889, 556, 556, 556, 556, 556, 278, 278, 278, 278, 611, 611, 611, 611, 611, 611, 611, 584, 611, 611, 611, 611, 611, 556, 611, 556],
40
40
41 'helveticaI'=>[278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 355, 556, 556, 889, 667, 191, 333, 333, 389, 584, 278, 333, 278, 278, 556, 556, 556, 556, 556, 556, 556, 556, 556, 556, 278, 278, 584, 584, 584, 556, 1015, 667, 667, 722, 722, 667, 611, 778, 722, 278, 500, 667, 556, 833, 722, 778, 667, 778, 722, 667, 611, 722, 667, 944, 667, 667, 611, 278, 278, 278, 469, 556, 333, 556, 556, 500, 556, 556, 278, 556, 556, 222, 222, 500, 222, 833, 556, 556, 556, 556, 333, 500, 278, 556, 500, 722, 500, 500, 500, 334, 260, 334, 584, 350, 556, 350, 222, 556, 333, 1000, 556, 556, 333, 1000, 667, 333, 1000, 350, 611, 350, 350, 222, 222, 333, 333, 350, 556, 1000, 333, 1000, 500, 333, 944, 350, 500, 667, 278, 333, 556, 556, 556, 556, 260, 556, 333, 737, 370, 556, 584, 333, 737, 333, 400, 584, 333, 333, 333, 556, 537, 278, 333, 333, 365, 556, 834, 834, 834, 611, 667, 667, 667, 667, 667, 667, 1000, 722, 667, 667, 667, 667, 278, 278, 278, 278, 722, 722, 778, 778, 778, 778, 778, 584, 778, 722, 722, 722, 722, 667, 667, 611, 556, 556, 556, 556, 556, 556, 889, 500, 556, 556, 556, 556, 278, 278, 278, 278, 556, 556, 556, 556, 556, 556, 556, 584, 611, 556, 556, 556, 556, 500, 556, 500],
41 'helveticaI'=>[278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 355, 556, 556, 889, 667, 191, 333, 333, 389, 584, 278, 333, 278, 278, 556, 556, 556, 556, 556, 556, 556, 556, 556, 556, 278, 278, 584, 584, 584, 556, 1015, 667, 667, 722, 722, 667, 611, 778, 722, 278, 500, 667, 556, 833, 722, 778, 667, 778, 722, 667, 611, 722, 667, 944, 667, 667, 611, 278, 278, 278, 469, 556, 333, 556, 556, 500, 556, 556, 278, 556, 556, 222, 222, 500, 222, 833, 556, 556, 556, 556, 333, 500, 278, 556, 500, 722, 500, 500, 500, 334, 260, 334, 584, 350, 556, 350, 222, 556, 333, 1000, 556, 556, 333, 1000, 667, 333, 1000, 350, 611, 350, 350, 222, 222, 333, 333, 350, 556, 1000, 333, 1000, 500, 333, 944, 350, 500, 667, 278, 333, 556, 556, 556, 556, 260, 556, 333, 737, 370, 556, 584, 333, 737, 333, 400, 584, 333, 333, 333, 556, 537, 278, 333, 333, 365, 556, 834, 834, 834, 611, 667, 667, 667, 667, 667, 667, 1000, 722, 667, 667, 667, 667, 278, 278, 278, 278, 722, 722, 778, 778, 778, 778, 778, 584, 778, 722, 722, 722, 722, 667, 667, 611, 556, 556, 556, 556, 556, 556, 889, 500, 556, 556, 556, 556, 278, 278, 278, 278, 556, 556, 556, 556, 556, 556, 556, 584, 611, 556, 556, 556, 556, 500, 556, 500],
42
42
43 'helveticaBI'=>[278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 333, 474, 556, 556, 889, 722, 238, 333, 333, 389, 584, 278, 333, 278, 278, 556, 556, 556, 556, 556, 556, 556, 556, 556, 556, 333, 333, 584, 584, 584, 611, 975, 722, 722, 722, 722, 667, 611, 778, 722, 278, 556, 722, 611, 833, 722, 778, 667, 778, 722, 667, 611, 722, 667, 944, 667, 667, 611, 333, 278, 333, 584, 556, 333, 556, 611, 556, 611, 556, 333, 611, 611, 278, 278, 556, 278, 889, 611, 611, 611, 611, 389, 556, 333, 611, 556, 778, 556, 556, 500, 389, 280, 389, 584, 350, 556, 350, 278, 556, 500, 1000, 556, 556, 333, 1000, 667, 333, 1000, 350, 611, 350, 350, 278, 278, 500, 500, 350, 556, 1000, 333, 1000, 556, 333, 944, 350, 500, 667, 278, 333, 556, 556, 556, 556, 280, 556, 333, 737, 370, 556, 584, 333, 737, 333, 400, 584, 333, 333, 333, 611, 556, 278, 333, 333, 365, 556, 834, 834, 834, 611, 722, 722, 722, 722, 722, 722, 1000, 722, 667, 667, 667, 667, 278, 278, 278, 278, 722, 722, 778, 778, 778, 778, 778, 584, 778, 722, 722, 722, 722, 667, 667, 611, 556, 556, 556, 556, 556, 556, 889, 556, 556, 556, 556, 556, 278, 278, 278, 278, 611, 611, 611, 611, 611, 611, 611, 584, 611, 611, 611, 611, 611, 556, 611, 556],
43 'helveticaBI'=>[278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 333, 474, 556, 556, 889, 722, 238, 333, 333, 389, 584, 278, 333, 278, 278, 556, 556, 556, 556, 556, 556, 556, 556, 556, 556, 333, 333, 584, 584, 584, 611, 975, 722, 722, 722, 722, 667, 611, 778, 722, 278, 556, 722, 611, 833, 722, 778, 667, 778, 722, 667, 611, 722, 667, 944, 667, 667, 611, 333, 278, 333, 584, 556, 333, 556, 611, 556, 611, 556, 333, 611, 611, 278, 278, 556, 278, 889, 611, 611, 611, 611, 389, 556, 333, 611, 556, 778, 556, 556, 500, 389, 280, 389, 584, 350, 556, 350, 278, 556, 500, 1000, 556, 556, 333, 1000, 667, 333, 1000, 350, 611, 350, 350, 278, 278, 500, 500, 350, 556, 1000, 333, 1000, 556, 333, 944, 350, 500, 667, 278, 333, 556, 556, 556, 556, 280, 556, 333, 737, 370, 556, 584, 333, 737, 333, 400, 584, 333, 333, 333, 611, 556, 278, 333, 333, 365, 556, 834, 834, 834, 611, 722, 722, 722, 722, 722, 722, 1000, 722, 667, 667, 667, 667, 278, 278, 278, 278, 722, 722, 778, 778, 778, 778, 778, 584, 778, 722, 722, 722, 722, 667, 667, 611, 556, 556, 556, 556, 556, 556, 889, 556, 556, 556, 556, 556, 278, 278, 278, 278, 611, 611, 611, 611, 611, 611, 611, 584, 611, 611, 611, 611, 611, 556, 611, 556],
44
44
45 'times'=>[250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 333, 408, 500, 500, 833, 778, 180, 333, 333, 500, 564, 250, 333, 250, 278, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 278, 278, 564, 564, 564, 444, 921, 722, 667, 667, 722, 611, 556, 722, 722, 333, 389, 722, 611, 889, 722, 722, 556, 722, 667, 556, 611, 722, 722, 944, 722, 722, 611, 333, 278, 333, 469, 500, 333, 444, 500, 444, 500, 444, 333, 500, 500, 278, 278, 500, 278, 778, 500, 500, 500, 500, 333, 389, 278, 500, 500, 722, 500, 500, 444, 480, 200, 480, 541, 350, 500, 350, 333, 500, 444, 1000, 500, 500, 333, 1000, 556, 333, 889, 350, 611, 350, 350, 333, 333, 444, 444, 350, 500, 1000, 333, 980, 389, 333, 722, 350, 444, 722, 250, 333, 500, 500, 500, 500, 200, 500, 333, 760, 276, 500, 564, 333, 760, 333, 400, 564, 300, 300, 333, 500, 453, 250, 333, 300, 310, 500, 750, 750, 750, 444, 722, 722, 722, 722, 722, 722, 889, 667, 611, 611, 611, 611, 333, 333, 333, 333, 722, 722, 722, 722, 722, 722, 722, 564, 722, 722, 722, 722, 722, 722, 556, 500, 444, 444, 444, 444, 444, 444, 667, 444, 444, 444, 444, 444, 278, 278, 278, 278, 500, 500, 500, 500, 500, 500, 500, 564, 500, 500, 500, 500, 500, 500, 500, 500],
45 'times'=>[250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 333, 408, 500, 500, 833, 778, 180, 333, 333, 500, 564, 250, 333, 250, 278, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 278, 278, 564, 564, 564, 444, 921, 722, 667, 667, 722, 611, 556, 722, 722, 333, 389, 722, 611, 889, 722, 722, 556, 722, 667, 556, 611, 722, 722, 944, 722, 722, 611, 333, 278, 333, 469, 500, 333, 444, 500, 444, 500, 444, 333, 500, 500, 278, 278, 500, 278, 778, 500, 500, 500, 500, 333, 389, 278, 500, 500, 722, 500, 500, 444, 480, 200, 480, 541, 350, 500, 350, 333, 500, 444, 1000, 500, 500, 333, 1000, 556, 333, 889, 350, 611, 350, 350, 333, 333, 444, 444, 350, 500, 1000, 333, 980, 389, 333, 722, 350, 444, 722, 250, 333, 500, 500, 500, 500, 200, 500, 333, 760, 276, 500, 564, 333, 760, 333, 400, 564, 300, 300, 333, 500, 453, 250, 333, 300, 310, 500, 750, 750, 750, 444, 722, 722, 722, 722, 722, 722, 889, 667, 611, 611, 611, 611, 333, 333, 333, 333, 722, 722, 722, 722, 722, 722, 722, 564, 722, 722, 722, 722, 722, 722, 556, 500, 444, 444, 444, 444, 444, 444, 667, 444, 444, 444, 444, 444, 278, 278, 278, 278, 500, 500, 500, 500, 500, 500, 500, 564, 500, 500, 500, 500, 500, 500, 500, 500],
46
46
47 'timesB'=>[250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 333, 555, 500, 500, 1000, 833, 278, 333, 333, 500, 570, 250, 333, 250, 278, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 333, 333, 570, 570, 570, 500, 930, 722, 667, 722, 722, 667, 611, 778, 778, 389, 500, 778, 667, 944, 722, 778, 611, 778, 722, 556, 667, 722, 722, 1000, 722, 722, 667, 333, 278, 333, 581, 500, 333, 500, 556, 444, 556, 444, 333, 500, 556, 278, 333, 556, 278, 833, 556, 500, 556, 556, 444, 389, 333, 556, 500, 722, 500, 500, 444, 394, 220, 394, 520, 350, 500, 350, 333, 500, 500, 1000, 500, 500, 333, 1000, 556, 333, 1000, 350, 667, 350, 350, 333, 333, 500, 500, 350, 500, 1000, 333, 1000, 389, 333, 722, 350, 444, 722, 250, 333, 500, 500, 500, 500, 220, 500, 333, 747, 300, 500, 570, 333, 747, 333, 400, 570, 300, 300, 333, 556, 540, 250, 333, 300, 330, 500, 750, 750, 750, 500, 722, 722, 722, 722, 722, 722, 1000, 722, 667, 667, 667, 667, 389, 389, 389, 389, 722, 722, 778, 778, 778, 778, 778, 570, 778, 722, 722, 722, 722, 722, 611, 556, 500, 500, 500, 500, 500, 500, 722, 444, 444, 444, 444, 444, 278, 278, 278, 278, 500, 556, 500, 500, 500, 500, 500, 570, 500, 556, 556, 556, 556, 500, 556, 500],
47 'timesB'=>[250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 333, 555, 500, 500, 1000, 833, 278, 333, 333, 500, 570, 250, 333, 250, 278, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 333, 333, 570, 570, 570, 500, 930, 722, 667, 722, 722, 667, 611, 778, 778, 389, 500, 778, 667, 944, 722, 778, 611, 778, 722, 556, 667, 722, 722, 1000, 722, 722, 667, 333, 278, 333, 581, 500, 333, 500, 556, 444, 556, 444, 333, 500, 556, 278, 333, 556, 278, 833, 556, 500, 556, 556, 444, 389, 333, 556, 500, 722, 500, 500, 444, 394, 220, 394, 520, 350, 500, 350, 333, 500, 500, 1000, 500, 500, 333, 1000, 556, 333, 1000, 350, 667, 350, 350, 333, 333, 500, 500, 350, 500, 1000, 333, 1000, 389, 333, 722, 350, 444, 722, 250, 333, 500, 500, 500, 500, 220, 500, 333, 747, 300, 500, 570, 333, 747, 333, 400, 570, 300, 300, 333, 556, 540, 250, 333, 300, 330, 500, 750, 750, 750, 500, 722, 722, 722, 722, 722, 722, 1000, 722, 667, 667, 667, 667, 389, 389, 389, 389, 722, 722, 778, 778, 778, 778, 778, 570, 778, 722, 722, 722, 722, 722, 611, 556, 500, 500, 500, 500, 500, 500, 722, 444, 444, 444, 444, 444, 278, 278, 278, 278, 500, 556, 500, 500, 500, 500, 500, 570, 500, 556, 556, 556, 556, 500, 556, 500],
48
48
49 'timesI'=>[250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 333, 420, 500, 500, 833, 778, 214, 333, 333, 500, 675, 250, 333, 250, 278, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 333, 333, 675, 675, 675, 500, 920, 611, 611, 667, 722, 611, 611, 722, 722, 333, 444, 667, 556, 833, 667, 722, 611, 722, 611, 500, 556, 722, 611, 833, 611, 556, 556, 389, 278, 389, 422, 500, 333, 500, 500, 444, 500, 444, 278, 500, 500, 278, 278, 444, 278, 722, 500, 500, 500, 500, 389, 389, 278, 500, 444, 667, 444, 444, 389, 400, 275, 400, 541, 350, 500, 350, 333, 500, 556, 889, 500, 500, 333, 1000, 500, 333, 944, 350, 556, 350, 350, 333, 333, 556, 556, 350, 500, 889, 333, 980, 389, 333, 667, 350, 389, 556, 250, 389, 500, 500, 500, 500, 275, 500, 333, 760, 276, 500, 675, 333, 760, 333, 400, 675, 300, 300, 333, 500, 523, 250, 333, 300, 310, 500, 750, 750, 750, 500, 611, 611, 611, 611, 611, 611, 889, 667, 611, 611, 611, 611, 333, 333, 333, 333, 722, 667, 722, 722, 722, 722, 722, 675, 722, 722, 722, 722, 722, 556, 611, 500, 500, 500, 500, 500, 500, 500, 667, 444, 444, 444, 444, 444, 278, 278, 278, 278, 500, 500, 500, 500, 500, 500, 500, 675, 500, 500, 500, 500, 500, 444, 500, 444],
49 'timesI'=>[250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 333, 420, 500, 500, 833, 778, 214, 333, 333, 500, 675, 250, 333, 250, 278, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 333, 333, 675, 675, 675, 500, 920, 611, 611, 667, 722, 611, 611, 722, 722, 333, 444, 667, 556, 833, 667, 722, 611, 722, 611, 500, 556, 722, 611, 833, 611, 556, 556, 389, 278, 389, 422, 500, 333, 500, 500, 444, 500, 444, 278, 500, 500, 278, 278, 444, 278, 722, 500, 500, 500, 500, 389, 389, 278, 500, 444, 667, 444, 444, 389, 400, 275, 400, 541, 350, 500, 350, 333, 500, 556, 889, 500, 500, 333, 1000, 500, 333, 944, 350, 556, 350, 350, 333, 333, 556, 556, 350, 500, 889, 333, 980, 389, 333, 667, 350, 389, 556, 250, 389, 500, 500, 500, 500, 275, 500, 333, 760, 276, 500, 675, 333, 760, 333, 400, 675, 300, 300, 333, 500, 523, 250, 333, 300, 310, 500, 750, 750, 750, 500, 611, 611, 611, 611, 611, 611, 889, 667, 611, 611, 611, 611, 333, 333, 333, 333, 722, 667, 722, 722, 722, 722, 722, 675, 722, 722, 722, 722, 722, 556, 611, 500, 500, 500, 500, 500, 500, 500, 667, 444, 444, 444, 444, 444, 278, 278, 278, 278, 500, 500, 500, 500, 500, 500, 500, 675, 500, 500, 500, 500, 500, 444, 500, 444],
50
50
51 'timesBI'=>[250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 389, 555, 500, 500, 833, 778, 278, 333, 333, 500, 570, 250, 333, 250, 278, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 333, 333, 570, 570, 570, 500, 832, 667, 667, 667, 722, 667, 667, 722, 778, 389, 500, 667, 611, 889, 722, 722, 611, 722, 667, 556, 611, 722, 667, 889, 667, 611, 611, 333, 278, 333, 570, 500, 333, 500, 500, 444, 500, 444, 333, 500, 556, 278, 278, 500, 278, 778, 556, 500, 500, 500, 389, 389, 278, 556, 444, 667, 500, 444, 389, 348, 220, 348, 570, 350, 500, 350, 333, 500, 500, 1000, 500, 500, 333, 1000, 556, 333, 944, 350, 611, 350, 350, 333, 333, 500, 500, 350, 500, 1000, 333, 1000, 389, 333, 722, 350, 389, 611, 250, 389, 500, 500, 500, 500, 220, 500, 333, 747, 266, 500, 606, 333, 747, 333, 400, 570, 300, 300, 333, 576, 500, 250, 333, 300, 300, 500, 750, 750, 750, 500, 667, 667, 667, 667, 667, 667, 944, 667, 667, 667, 667, 667, 389, 389, 389, 389, 722, 722, 722, 722, 722, 722, 722, 570, 722, 722, 722, 722, 722, 611, 611, 500, 500, 500, 500, 500, 500, 500, 722, 444, 444, 444, 444, 444, 278, 278, 278, 278, 500, 556, 500, 500, 500, 500, 500, 570, 500, 556, 556, 556, 556, 444, 500, 444],
51 'timesBI'=>[250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 389, 555, 500, 500, 833, 778, 278, 333, 333, 500, 570, 250, 333, 250, 278, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 333, 333, 570, 570, 570, 500, 832, 667, 667, 667, 722, 667, 667, 722, 778, 389, 500, 667, 611, 889, 722, 722, 611, 722, 667, 556, 611, 722, 667, 889, 667, 611, 611, 333, 278, 333, 570, 500, 333, 500, 500, 444, 500, 444, 333, 500, 556, 278, 278, 500, 278, 778, 556, 500, 500, 500, 389, 389, 278, 556, 444, 667, 500, 444, 389, 348, 220, 348, 570, 350, 500, 350, 333, 500, 500, 1000, 500, 500, 333, 1000, 556, 333, 944, 350, 611, 350, 350, 333, 333, 500, 500, 350, 500, 1000, 333, 1000, 389, 333, 722, 350, 389, 611, 250, 389, 500, 500, 500, 500, 220, 500, 333, 747, 266, 500, 606, 333, 747, 333, 400, 570, 300, 300, 333, 576, 500, 250, 333, 300, 300, 500, 750, 750, 750, 500, 667, 667, 667, 667, 667, 667, 944, 667, 667, 667, 667, 667, 389, 389, 389, 389, 722, 722, 722, 722, 722, 722, 722, 570, 722, 722, 722, 722, 722, 611, 611, 500, 500, 500, 500, 500, 500, 500, 722, 444, 444, 444, 444, 444, 278, 278, 278, 278, 500, 556, 500, 500, 500, 500, 500, 570, 500, 556, 556, 556, 556, 444, 500, 444],
52
52
53 'symbol'=>[250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 333, 713, 500, 549, 833, 778, 439, 333, 333, 500, 549, 250, 549, 250, 278, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 278, 278, 549, 549, 549, 444, 549, 722, 667, 722, 612, 611, 763, 603, 722, 333, 631, 722, 686, 889, 722, 722, 768, 741, 556, 592, 611, 690, 439, 768, 645, 795, 611, 333, 863, 333, 658, 500, 500, 631, 549, 549, 494, 439, 521, 411, 603, 329, 603, 549, 549, 576, 521, 549, 549, 521, 549, 603, 439, 576, 713, 686, 493, 686, 494, 480, 200, 480, 549, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 750, 620, 247, 549, 167, 713, 500, 753, 753, 753, 753, 1042, 987, 603, 987, 603, 400, 549, 411, 549, 549, 713, 494, 460, 549, 549, 549, 549, 1000, 603, 1000, 658, 823, 686, 795, 987, 768, 768, 823, 768, 768, 713, 713, 713, 713, 713, 713, 713, 768, 713, 790, 790, 890, 823, 549, 250, 713, 603, 603, 1042, 987, 603, 987, 603, 494, 329, 790, 790, 786, 713, 384, 384, 384, 384, 384, 384, 494, 494, 494, 494, 0, 329, 274, 686, 686, 686, 384, 384, 384, 384, 384, 384, 494, 494, 494, 0],
53 'symbol'=>[250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 333, 713, 500, 549, 833, 778, 439, 333, 333, 500, 549, 250, 549, 250, 278, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 278, 278, 549, 549, 549, 444, 549, 722, 667, 722, 612, 611, 763, 603, 722, 333, 631, 722, 686, 889, 722, 722, 768, 741, 556, 592, 611, 690, 439, 768, 645, 795, 611, 333, 863, 333, 658, 500, 500, 631, 549, 549, 494, 439, 521, 411, 603, 329, 603, 549, 549, 576, 521, 549, 549, 521, 549, 603, 439, 576, 713, 686, 493, 686, 494, 480, 200, 480, 549, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 750, 620, 247, 549, 167, 713, 500, 753, 753, 753, 753, 1042, 987, 603, 987, 603, 400, 549, 411, 549, 549, 713, 494, 460, 549, 549, 549, 549, 1000, 603, 1000, 658, 823, 686, 795, 987, 768, 768, 823, 768, 768, 713, 713, 713, 713, 713, 713, 713, 768, 713, 790, 790, 890, 823, 549, 250, 713, 603, 603, 1042, 987, 603, 987, 603, 494, 329, 790, 790, 786, 713, 384, 384, 384, 384, 384, 384, 494, 494, 494, 494, 0, 329, 274, 686, 686, 686, 384, 384, 384, 384, 384, 384, 494, 494, 494, 0],
54
54
55 'zapfdingbats'=>[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 278, 974, 961, 974, 980, 719, 789, 790, 791, 690, 960, 939, 549, 855, 911, 933, 911, 945, 974, 755, 846, 762, 761, 571, 677, 763, 760, 759, 754, 494, 552, 537, 577, 692, 786, 788, 788, 790, 793, 794, 816, 823, 789, 841, 823, 833, 816, 831, 923, 744, 723, 749, 790, 792, 695, 776, 768, 792, 759, 707, 708, 682, 701, 826, 815, 789, 789, 707, 687, 696, 689, 786, 787, 713, 791, 785, 791, 873, 761, 762, 762, 759, 759, 892, 892, 788, 784, 438, 138, 277, 415, 392, 392, 668, 668, 0, 390, 390, 317, 317, 276, 276, 509, 509, 410, 410, 234, 234, 334, 334, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 732, 544, 544, 910, 667, 760, 760, 776, 595, 694, 626, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 894, 838, 1016, 458, 748, 924, 748, 918, 927, 928, 928, 834, 873, 828, 924, 924, 917, 930, 931, 463, 883, 836, 836, 867, 867, 696, 696, 874, 0, 874, 760, 946, 771, 865, 771, 888, 967, 888, 831, 873, 927, 970, 918, 0]
55 'zapfdingbats'=>[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 278, 974, 961, 974, 980, 719, 789, 790, 791, 690, 960, 939, 549, 855, 911, 933, 911, 945, 974, 755, 846, 762, 761, 571, 677, 763, 760, 759, 754, 494, 552, 537, 577, 692, 786, 788, 788, 790, 793, 794, 816, 823, 789, 841, 823, 833, 816, 831, 923, 744, 723, 749, 790, 792, 695, 776, 768, 792, 759, 707, 708, 682, 701, 826, 815, 789, 789, 707, 687, 696, 689, 786, 787, 713, 791, 785, 791, 873, 761, 762, 762, 759, 759, 892, 892, 788, 784, 438, 138, 277, 415, 392, 392, 668, 668, 0, 390, 390, 317, 317, 276, 276, 509, 509, 410, 410, 234, 234, 334, 334, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 732, 544, 544, 910, 667, 760, 760, 776, 595, 694, 626, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 894, 838, 1016, 458, 748, 924, 748, 918, 927, 928, 928, 834, 873, 828, 924, 924, 917, 930, 931, 463, 883, 836, 836, 867, 867, 696, 696, 874, 0, 874, 760, 946, 771, 865, 771, 888, 967, 888, 831, 873, 927, 970, 918, 0]
56 }
56 }
57
57
58 def initialize(orientation='P', unit='mm', format='A4')
58 def initialize(orientation='P', unit='mm', format='A4')
59 # Initialization of properties
59 # Initialization of properties
60 @page=0
60 @page=0
61 @n=2
61 @n=2
62 @buffer=''
62 @buffer=''
63 @pages=[]
63 @pages=[]
64 @OrientationChanges=[]
64 @OrientationChanges=[]
65 @state=0
65 @state=0
66 @fonts={}
66 @fonts={}
67 @FontFiles={}
67 @FontFiles={}
68 @diffs=[]
68 @diffs=[]
69 @images={}
69 @images={}
70 @links=[]
70 @links=[]
71 @PageLinks={}
71 @PageLinks={}
72 @InFooter=false
72 @InFooter=false
73 @FontFamily=''
73 @FontFamily=''
74 @FontStyle=''
74 @FontStyle=''
75 @FontSizePt=12
75 @FontSizePt=12
76 @underline= false
76 @underline= false
77 @DrawColor='0 G'
77 @DrawColor='0 G'
78 @FillColor='0 g'
78 @FillColor='0 g'
79 @TextColor='0 g'
79 @TextColor='0 g'
80 @ColorFlag=false
80 @ColorFlag=false
81 @ws=0
81 @ws=0
82 @offsets=[]
82 @offsets=[]
83
83
84 # Standard fonts
84 # Standard fonts
85 @CoreFonts={}
85 @CoreFonts={}
86 @CoreFonts['courier']='Courier'
86 @CoreFonts['courier']='Courier'
87 @CoreFonts['courierB']='Courier-Bold'
87 @CoreFonts['courierB']='Courier-Bold'
88 @CoreFonts['courierI']='Courier-Oblique'
88 @CoreFonts['courierI']='Courier-Oblique'
89 @CoreFonts['courierBI']='Courier-BoldOblique'
89 @CoreFonts['courierBI']='Courier-BoldOblique'
90 @CoreFonts['helvetica']='Helvetica'
90 @CoreFonts['helvetica']='Helvetica'
91 @CoreFonts['helveticaB']='Helvetica-Bold'
91 @CoreFonts['helveticaB']='Helvetica-Bold'
92 @CoreFonts['helveticaI']='Helvetica-Oblique'
92 @CoreFonts['helveticaI']='Helvetica-Oblique'
93 @CoreFonts['helveticaBI']='Helvetica-BoldOblique'
93 @CoreFonts['helveticaBI']='Helvetica-BoldOblique'
94 @CoreFonts['times']='Times-Roman'
94 @CoreFonts['times']='Times-Roman'
95 @CoreFonts['timesB']='Times-Bold'
95 @CoreFonts['timesB']='Times-Bold'
96 @CoreFonts['timesI']='Times-Italic'
96 @CoreFonts['timesI']='Times-Italic'
97 @CoreFonts['timesBI']='Times-BoldItalic'
97 @CoreFonts['timesBI']='Times-BoldItalic'
98 @CoreFonts['symbol']='Symbol'
98 @CoreFonts['symbol']='Symbol'
99 @CoreFonts['zapfdingbats']='ZapfDingbats'
99 @CoreFonts['zapfdingbats']='ZapfDingbats'
100
100
101 # Scale factor
101 # Scale factor
102 if unit=='pt'
102 if unit=='pt'
103 @k=1
103 @k=1
104 elsif unit=='mm'
104 elsif unit=='mm'
105 @k=72/25.4
105 @k=72/25.4
106 elsif unit=='cm'
106 elsif unit=='cm'
107 @k=72/2.54;
107 @k=72/2.54;
108 elsif unit=='in'
108 elsif unit=='in'
109 @k=72
109 @k=72
110 else
110 else
111 raise 'Incorrect unit: '+unit
111 raise 'Incorrect unit: '+unit
112 end
112 end
113
113
114 # Page format
114 # Page format
115 if format.is_a? String
115 if format.is_a? String
116 format.downcase!
116 format.downcase!
117 if format=='a3'
117 if format=='a3'
118 format=[841.89,1190.55]
118 format=[841.89,1190.55]
119 elsif format=='a4'
119 elsif format=='a4'
120 format=[595.28,841.89]
120 format=[595.28,841.89]
121 elsif format=='a5'
121 elsif format=='a5'
122 format=[420.94,595.28]
122 format=[420.94,595.28]
123 elsif format=='letter'
123 elsif format=='letter'
124 format=[612,792]
124 format=[612,792]
125 elsif format=='legal'
125 elsif format=='legal'
126 format=[612,1008]
126 format=[612,1008]
127 else
127 else
128 raise 'Unknown page format: '+format
128 raise 'Unknown page format: '+format
129 end
129 end
130 @fwPt,@fhPt=format
130 @fwPt,@fhPt=format
131 else
131 else
132 @fwPt=format[0]*@k
132 @fwPt=format[0]*@k
133 @fhPt=format[1]*@k
133 @fhPt=format[1]*@k
134 end
134 end
135 @fw=@fwPt/@k;
135 @fw=@fwPt/@k;
136 @fh=@fhPt/@k;
136 @fh=@fhPt/@k;
137
137
138 # Page orientation
138 # Page orientation
139 orientation.downcase!
139 orientation.downcase!
140 if orientation=='p' or orientation=='portrait'
140 if orientation=='p' or orientation=='portrait'
141 @DefOrientation='P'
141 @DefOrientation='P'
142 @wPt=@fwPt
142 @wPt=@fwPt
143 @hPt=@fhPt
143 @hPt=@fhPt
144 elsif orientation=='l' or orientation=='landscape'
144 elsif orientation=='l' or orientation=='landscape'
145 @DefOrientation='L'
145 @DefOrientation='L'
146 @wPt=@fhPt
146 @wPt=@fhPt
147 @hPt=@fwPt
147 @hPt=@fwPt
148 else
148 else
149 raise 'Incorrect orientation: '+orientation
149 raise 'Incorrect orientation: '+orientation
150 end
150 end
151 @CurOrientation=@DefOrientation
151 @CurOrientation=@DefOrientation
152 @w=@wPt/@k
152 @w=@wPt/@k
153 @h=@hPt/@k
153 @h=@hPt/@k
154
154
155 # Page margins (1 cm)
155 # Page margins (1 cm)
156 margin=28.35/@k
156 margin=28.35/@k
157 SetMargins(margin,margin)
157 SetMargins(margin,margin)
158 # Interior cell margin (1 mm)
158 # Interior cell margin (1 mm)
159 @cMargin=margin/10
159 @cMargin=margin/10
160 # Line width (0.2 mm)
160 # Line width (0.2 mm)
161 @LineWidth=0.567/@k
161 @LineWidth=0.567/@k
162 # Automatic page break
162 # Automatic page break
163 SetAutoPageBreak(true,2*margin)
163 SetAutoPageBreak(true,2*margin)
164 # Full width display mode
164 # Full width display mode
165 SetDisplayMode('fullwidth')
165 SetDisplayMode('fullwidth')
166 # Enable compression
166 # Enable compression
167 SetCompression(true)
167 SetCompression(true)
168 # Set default PDF version number
168 # Set default PDF version number
169 @PDFVersion='1.3'
169 @PDFVersion='1.3'
170 end
170 end
171
171
172 def SetMargins(left, top, right=-1)
172 def SetMargins(left, top, right=-1)
173 # Set left, top and right margins
173 # Set left, top and right margins
174 @lMargin=left
174 @lMargin=left
175 @tMargin=top
175 @tMargin=top
176 right=left if right==-1
176 right=left if right==-1
177 @rMargin=right
177 @rMargin=right
178 end
178 end
179
179
180 def SetLeftMargin(margin)
180 def SetLeftMargin(margin)
181 # Set left margin
181 # Set left margin
182 @lMargin=margin
182 @lMargin=margin
183 @x=margin if @page>0 and @x<margin
183 @x=margin if @page>0 and @x<margin
184 end
184 end
185
185
186 def SetTopMargin(margin)
186 def SetTopMargin(margin)
187 # Set top margin
187 # Set top margin
188 @tMargin=margin
188 @tMargin=margin
189 end
189 end
190
190
191 def SetRightMargin(margin)
191 def SetRightMargin(margin)
192 #Set right margin
192 #Set right margin
193 @rMargin=margin
193 @rMargin=margin
194 end
194 end
195
195
196 def SetAutoPageBreak(auto, margin=0)
196 def SetAutoPageBreak(auto, margin=0)
197 # Set auto page break mode and triggering margin
197 # Set auto page break mode and triggering margin
198 @AutoPageBreak=auto
198 @AutoPageBreak=auto
199 @bMargin=margin
199 @bMargin=margin
200 @PageBreakTrigger=@h-margin
200 @PageBreakTrigger=@h-margin
201 end
201 end
202
202
203 def SetDisplayMode(zoom, layout='continuous')
203 def SetDisplayMode(zoom, layout='continuous')
204 # Set display mode in viewer
204 # Set display mode in viewer
205 if zoom=='fullpage' or zoom=='fullwidth' or zoom=='real' or
205 if zoom=='fullpage' or zoom=='fullwidth' or zoom=='real' or
206 zoom=='default' or not zoom.kind_of? String
206 zoom=='default' or not zoom.kind_of? String
207
207
208 @ZoomMode=zoom;
208 @ZoomMode=zoom;
209 elsif zoom=='zoom'
209 elsif zoom=='zoom'
210 @ZoomMode=layout
210 @ZoomMode=layout
211 else
211 else
212 raise 'Incorrect zoom display mode: '+zoom
212 raise 'Incorrect zoom display mode: '+zoom
213 end
213 end
214 if layout=='single' or layout=='continuous' or layout=='two' or
214 if layout=='single' or layout=='continuous' or layout=='two' or
215 layout=='default'
215 layout=='default'
216
216
217 @LayoutMode=layout
217 @LayoutMode=layout
218 elsif zoom!='zoom'
218 elsif zoom!='zoom'
219 raise 'Incorrect layout display mode: '+layout
219 raise 'Incorrect layout display mode: '+layout
220 end
220 end
221 end
221 end
222
222
223 def SetCompression(compress)
223 def SetCompression(compress)
224 # Set page compression
224 # Set page compression
225 @compress = compress
225 @compress = compress
226 end
226 end
227
227
228 def SetTitle(title)
228 def SetTitle(title)
229 # Title of document
229 # Title of document
230 @title=title
230 @title=title
231 end
231 end
232
232
233 def SetSubject(subject)
233 def SetSubject(subject)
234 # Subject of document
234 # Subject of document
235 @subject=subject
235 @subject=subject
236 end
236 end
237
237
238 def SetAuthor(author)
238 def SetAuthor(author)
239 # Author of document
239 # Author of document
240 @author=author
240 @author=author
241 end
241 end
242
242
243 def SetKeywords(keywords)
243 def SetKeywords(keywords)
244 # Keywords of document
244 # Keywords of document
245 @keywords=keywords
245 @keywords=keywords
246 end
246 end
247
247
248 def SetCreator(creator)
248 def SetCreator(creator)
249 # Creator of document
249 # Creator of document
250 @creator=creator
250 @creator=creator
251 end
251 end
252
252
253 def AliasNbPages(aliasnb='{nb}')
253 def AliasNbPages(aliasnb='{nb}')
254 # Define an alias for total number of pages
254 # Define an alias for total number of pages
255 @AliasNbPages=aliasnb
255 @AliasNbPages=aliasnb
256 end
256 end
257
257
258 def Error(msg)
258 def Error(msg)
259 raise 'FPDF error: '+msg
259 raise 'FPDF error: '+msg
260 end
260 end
261
261
262 def Open
262 def Open
263 # Begin document
263 # Begin document
264 @state=1
264 @state=1
265 end
265 end
266
266
267 def Close
267 def Close
268 # Terminate document
268 # Terminate document
269 return if @state==3
269 return if @state==3
270 self.AddPage if @page==0
270 self.AddPage if @page==0
271 # Page footer
271 # Page footer
272 @InFooter=true
272 @InFooter=true
273 self.Footer
273 self.Footer
274 @InFooter=false
274 @InFooter=false
275 # Close page
275 # Close page
276 endpage
276 endpage
277 # Close document
277 # Close document
278 enddoc
278 enddoc
279 end
279 end
280
280
281 def AddPage(orientation='')
281 def AddPage(orientation='')
282 # Start a new page
282 # Start a new page
283 self.Open if @state==0
283 self.Open if @state==0
284 family=@FontFamily
284 family=@FontFamily
285 style=@FontStyle+(@underline ? 'U' : '')
285 style=@FontStyle+(@underline ? 'U' : '')
286 size=@FontSizePt
286 size=@FontSizePt
287 lw=@LineWidth
287 lw=@LineWidth
288 dc=@DrawColor
288 dc=@DrawColor
289 fc=@FillColor
289 fc=@FillColor
290 tc=@TextColor
290 tc=@TextColor
291 cf=@ColorFlag
291 cf=@ColorFlag
292 if @page>0
292 if @page>0
293 # Page footer
293 # Page footer
294 @InFooter=true
294 @InFooter=true
295 self.Footer
295 self.Footer
296 @InFooter=false
296 @InFooter=false
297 # Close page
297 # Close page
298 endpage
298 endpage
299 end
299 end
300 # Start new page
300 # Start new page
301 beginpage(orientation)
301 beginpage(orientation)
302 # Set line cap style to square
302 # Set line cap style to square
303 out('2 J')
303 out('2 J')
304 # Set line width
304 # Set line width
305 @LineWidth=lw
305 @LineWidth=lw
306 out(sprintf('%.2f w',lw*@k))
306 out(sprintf('%.2f w',lw*@k))
307 # Set font
307 # Set font
308 SetFont(family,style,size) if family
308 SetFont(family,style,size) if family
309 # Set colors
309 # Set colors
310 @DrawColor=dc
310 @DrawColor=dc
311 out(dc) if dc!='0 G'
311 out(dc) if dc!='0 G'
312 @FillColor=fc
312 @FillColor=fc
313 out(fc) if fc!='0 g'
313 out(fc) if fc!='0 g'
314 @TextColor=tc
314 @TextColor=tc
315 @ColorFlag=cf
315 @ColorFlag=cf
316 # Page header
316 # Page header
317 self.Header
317 self.Header
318 # Restore line width
318 # Restore line width
319 if @LineWidth!=lw
319 if @LineWidth!=lw
320 @LineWidth=lw
320 @LineWidth=lw
321 out(sprintf('%.2f w',lw*@k))
321 out(sprintf('%.2f w',lw*@k))
322 end
322 end
323 # Restore font
323 # Restore font
324 self.SetFont(family,style,size) if family
324 self.SetFont(family,style,size) if family
325 # Restore colors
325 # Restore colors
326 if @DrawColor!=dc
326 if @DrawColor!=dc
327 @DrawColor=dc
327 @DrawColor=dc
328 out(dc)
328 out(dc)
329 end
329 end
330 if @FillColor!=fc
330 if @FillColor!=fc
331 @FillColor=fc
331 @FillColor=fc
332 out(fc)
332 out(fc)
333 end
333 end
334 @TextColor=tc
334 @TextColor=tc
335 @ColorFlag=cf
335 @ColorFlag=cf
336 end
336 end
337
337
338 def Header
338 def Header
339 # To be implemented in your inherited class
339 # To be implemented in your inherited class
340 end
340 end
341
341
342 def Footer
342 def Footer
343 # To be implemented in your inherited class
343 # To be implemented in your inherited class
344 end
344 end
345
345
346 def PageNo
346 def PageNo
347 # Get current page number
347 # Get current page number
348 @page
348 @page
349 end
349 end
350
350
351 def SetDrawColor(r,g=-1,b=-1)
351 def SetDrawColor(r,g=-1,b=-1)
352 # Set color for all stroking operations
352 # Set color for all stroking operations
353 if (r==0 and g==0 and b==0) or g==-1
353 if (r==0 and g==0 and b==0) or g==-1
354 @DrawColor=sprintf('%.3f G',r/255.0)
354 @DrawColor=sprintf('%.3f G',r/255.0)
355 else
355 else
356 @DrawColor=sprintf('%.3f %.3f %.3f RG',r/255.0,g/255.0,b/255.0)
356 @DrawColor=sprintf('%.3f %.3f %.3f RG',r/255.0,g/255.0,b/255.0)
357 end
357 end
358 out(@DrawColor) if(@page>0)
358 out(@DrawColor) if(@page>0)
359 end
359 end
360
360
361 def SetFillColor(r,g=-1,b=-1)
361 def SetFillColor(r,g=-1,b=-1)
362 # Set color for all filling operations
362 # Set color for all filling operations
363 if (r==0 and g==0 and b==0) or g==-1
363 if (r==0 and g==0 and b==0) or g==-1
364 @FillColor=sprintf('%.3f g',r/255.0)
364 @FillColor=sprintf('%.3f g',r/255.0)
365 else
365 else
366 @FillColor=sprintf('%.3f %.3f %.3f rg',r/255.0,g/255.0,b/255.0)
366 @FillColor=sprintf('%.3f %.3f %.3f rg',r/255.0,g/255.0,b/255.0)
367 end
367 end
368 @ColorFlag=(@FillColor!=@TextColor)
368 @ColorFlag=(@FillColor!=@TextColor)
369 out(@FillColor) if(@page>0)
369 out(@FillColor) if(@page>0)
370 end
370 end
371
371
372 def SetTextColor(r,g=-1,b=-1)
372 def SetTextColor(r,g=-1,b=-1)
373 # Set color for text
373 # Set color for text
374 if (r==0 and g==0 and b==0) or g==-1
374 if (r==0 and g==0 and b==0) or g==-1
375 @TextColor=sprintf('%.3f g',r/255.0)
375 @TextColor=sprintf('%.3f g',r/255.0)
376 else
376 else
377 @TextColor=sprintf('%.3f %.3f %.3f rg',r/255.0,g/255.0,b/255.0)
377 @TextColor=sprintf('%.3f %.3f %.3f rg',r/255.0,g/255.0,b/255.0)
378 end
378 end
379 @ColorFlag=(@FillColor!=@TextColor)
379 @ColorFlag=(@FillColor!=@TextColor)
380 end
380 end
381
382 def GetCharWidth(widths, index)
383 if index.is_a?(String)
384 widths[index.ord]
385 else
386 widths[index]
387 end
388 end
381
389
382 def GetStringWidth(s)
390 def GetStringWidth(s)
383 # Get width of a string in the current font
391 # Get width of a string in the current font
384 cw=@CurrentFont['cw']
392 cw=@CurrentFont['cw']
385 w=0
393 w=0
386 s.each_byte do |c|
394 s.each_byte do |c|
387 w=w+cw[c]
395 w=w+GetCharWidth(cw, c)
388 end
396 end
389 w*@FontSize/1000.0
397 w*@FontSize/1000.0
390 end
398 end
391
399
392 def SetLineWidth(width)
400 def SetLineWidth(width)
393 # Set line width
401 # Set line width
394 @LineWidth=width
402 @LineWidth=width
395 out(sprintf('%.2f w',width*@k)) if @page>0
403 out(sprintf('%.2f w',width*@k)) if @page>0
396 end
404 end
397
405
398 def Line(x1, y1, x2, y2)
406 def Line(x1, y1, x2, y2)
399 # Draw a line
407 # Draw a line
400 out(sprintf('%.2f %.2f m %.2f %.2f l S',
408 out(sprintf('%.2f %.2f m %.2f %.2f l S',
401 x1*@k,(@h-y1)*@k,x2*@k,(@h-y2)*@k))
409 x1*@k,(@h-y1)*@k,x2*@k,(@h-y2)*@k))
402 end
410 end
403
411
404 def Rect(x, y, w, h, style='')
412 def Rect(x, y, w, h, style='')
405 # Draw a rectangle
413 # Draw a rectangle
406 if style=='F'
414 if style=='F'
407 op='f'
415 op='f'
408 elsif style=='FD' or style=='DF'
416 elsif style=='FD' or style=='DF'
409 op='B'
417 op='B'
410 else
418 else
411 op='S'
419 op='S'
412 end
420 end
413 out(sprintf('%.2f %.2f %.2f %.2f re %s', x*@k,(@h-y)*@k,w*@k,-h*@k,op))
421 out(sprintf('%.2f %.2f %.2f %.2f re %s', x*@k,(@h-y)*@k,w*@k,-h*@k,op))
414 end
422 end
415
423
416 def AddFont(family, style='', file='')
424 def AddFont(family, style='', file='')
417 # Add a TrueType or Type1 font
425 # Add a TrueType or Type1 font
418 family = family.downcase
426 family = family.downcase
419 family = 'helvetica' if family == 'arial'
427 family = 'helvetica' if family == 'arial'
420
428
421 style = style.upcase
429 style = style.upcase
422 style = 'BI' if style == 'IB'
430 style = 'BI' if style == 'IB'
423
431
424 fontkey = family + style
432 fontkey = family + style
425
433
426 if @fonts.has_key?(fontkey)
434 if @fonts.has_key?(fontkey)
427 self.Error("Font already added: #{family} #{style}")
435 self.Error("Font already added: #{family} #{style}")
428 end
436 end
429
437
430 file = family.gsub(' ', '') + style.downcase + '.rb' if file == ''
438 file = family.gsub(' ', '') + style.downcase + '.rb' if file == ''
431
439
432 if self.class.const_defined? 'FPDF_FONTPATH'
440 if self.class.const_defined? 'FPDF_FONTPATH'
433 if FPDF_FONTPATH[-1,1] == '/'
441 if FPDF_FONTPATH[-1,1] == '/'
434 file = FPDF_FONTPATH + file
442 file = FPDF_FONTPATH + file
435 else
443 else
436 file = FPDF_FONTPATH + '/' + file
444 file = FPDF_FONTPATH + '/' + file
437 end
445 end
438 end
446 end
439
447
440 # Changed from "require file" to fix bug reported by Hans Allis.
448 # Changed from "require file" to fix bug reported by Hans Allis.
441 load file
449 load file
442
450
443 if FontDef.desc.nil?
451 if FontDef.desc.nil?
444 self.Error("Could not include font definition file #{file}")
452 self.Error("Could not include font definition file #{file}")
445 end
453 end
446
454
447 i = @fonts.length + 1
455 i = @fonts.length + 1
448
456
449 @fonts[fontkey] = {'i' => i,
457 @fonts[fontkey] = {'i' => i,
450 'type' => FontDef.type,
458 'type' => FontDef.type,
451 'name' => FontDef.name,
459 'name' => FontDef.name,
452 'desc' => FontDef.desc,
460 'desc' => FontDef.desc,
453 'up' => FontDef.up,
461 'up' => FontDef.up,
454 'ut' => FontDef.ut,
462 'ut' => FontDef.ut,
455 'cw' => FontDef.cw,
463 'cw' => FontDef.cw,
456 'enc' => FontDef.enc,
464 'enc' => FontDef.enc,
457 'file' => FontDef.file
465 'file' => FontDef.file
458 }
466 }
459
467
460 if FontDef.diff
468 if FontDef.diff
461 # Search existing encodings
469 # Search existing encodings
462 unless @diffs.include?(FontDef.diff)
470 unless @diffs.include?(FontDef.diff)
463 @diffs.push(FontDef.diff)
471 @diffs.push(FontDef.diff)
464 @fonts[fontkey]['diff'] = @diffs.length - 1
472 @fonts[fontkey]['diff'] = @diffs.length - 1
465 end
473 end
466 end
474 end
467
475
468 if FontDef.file
476 if FontDef.file
469 if FontDef.type == 'TrueType'
477 if FontDef.type == 'TrueType'
470 @FontFiles[FontDef.file] = {'length1' => FontDef.originalsize}
478 @FontFiles[FontDef.file] = {'length1' => FontDef.originalsize}
471 else
479 else
472 @FontFiles[FontDef.file] = {'length1' => FontDef.size1, 'length2' => FontDef.size2}
480 @FontFiles[FontDef.file] = {'length1' => FontDef.size1, 'length2' => FontDef.size2}
473 end
481 end
474 end
482 end
475
483
476 return self
484 return self
477 end
485 end
478
486
479 def SetFont(family, style='', size=0)
487 def SetFont(family, style='', size=0)
480 # Select a font; size given in points
488 # Select a font; size given in points
481 family.downcase!
489 family.downcase!
482 family=@FontFamily if family==''
490 family=@FontFamily if family==''
483 if family=='arial'
491 if family=='arial'
484 family='helvetica'
492 family='helvetica'
485 elsif family=='symbol' or family=='zapfdingbats'
493 elsif family=='symbol' or family=='zapfdingbats'
486 style=''
494 style=''
487 end
495 end
488 style.upcase!
496 style.upcase!
489 unless style.index('U').nil?
497 unless style.index('U').nil?
490 @underline=true
498 @underline=true
491 style.gsub!('U','')
499 style.gsub!('U','')
492 else
500 else
493 @underline=false;
501 @underline=false;
494 end
502 end
495 style='BI' if style=='IB'
503 style='BI' if style=='IB'
496 size=@FontSizePt if size==0
504 size=@FontSizePt if size==0
497 # Test if font is already selected
505 # Test if font is already selected
498 return if @FontFamily==family and
506 return if @FontFamily==family and
499 @FontStyle==style and @FontSizePt==size
507 @FontStyle==style and @FontSizePt==size
500 # Test if used for the first time
508 # Test if used for the first time
501 fontkey=family+style
509 fontkey=family+style
502 unless @fonts.has_key?(fontkey)
510 unless @fonts.has_key?(fontkey)
503 if @CoreFonts.has_key?(fontkey)
511 if @CoreFonts.has_key?(fontkey)
504 unless Charwidths.has_key?(fontkey)
512 unless Charwidths.has_key?(fontkey)
505 raise 'Font unavailable'
513 raise 'Font unavailable'
506 end
514 end
507 @fonts[fontkey]={
515 @fonts[fontkey]={
508 'i'=>@fonts.size,
516 'i'=>@fonts.size,
509 'type'=>'core',
517 'type'=>'core',
510 'name'=>@CoreFonts[fontkey],
518 'name'=>@CoreFonts[fontkey],
511 'up'=>-100,
519 'up'=>-100,
512 'ut'=>50,
520 'ut'=>50,
513 'cw'=>Charwidths[fontkey]}
521 'cw'=>Charwidths[fontkey]}
514 else
522 else
515 raise 'Font unavailable'
523 raise 'Font unavailable'
516 end
524 end
517 end
525 end
518
526
519 #Select it
527 #Select it
520 @FontFamily=family
528 @FontFamily=family
521 @FontStyle=style;
529 @FontStyle=style;
522 @FontSizePt=size
530 @FontSizePt=size
523 @FontSize=size/@k;
531 @FontSize=size/@k;
524 @CurrentFont=@fonts[fontkey]
532 @CurrentFont=@fonts[fontkey]
525 if @page>0
533 if @page>0
526 out(sprintf('BT /F%d %.2f Tf ET', @CurrentFont['i'], @FontSizePt))
534 out(sprintf('BT /F%d %.2f Tf ET', @CurrentFont['i'], @FontSizePt))
527 end
535 end
528 end
536 end
529
537
530 def SetFontSize(size)
538 def SetFontSize(size)
531 # Set font size in points
539 # Set font size in points
532 return if @FontSizePt==size
540 return if @FontSizePt==size
533 @FontSizePt=size
541 @FontSizePt=size
534 @FontSize=size/@k
542 @FontSize=size/@k
535 if @page>0
543 if @page>0
536 out(sprintf('BT /F%d %.2f Tf ET',@CurrentFont['i'],@FontSizePt))
544 out(sprintf('BT /F%d %.2f Tf ET',@CurrentFont['i'],@FontSizePt))
537 end
545 end
538 end
546 end
539
547
540 def AddLink
548 def AddLink
541 # Create a new internal link
549 # Create a new internal link
542 @links.push([0, 0])
550 @links.push([0, 0])
543 @links.size
551 @links.size
544 end
552 end
545
553
546 def SetLink(link, y=0, page=-1)
554 def SetLink(link, y=0, page=-1)
547 # Set destination of internal link
555 # Set destination of internal link
548 y=@y if y==-1
556 y=@y if y==-1
549 page=@page if page==-1
557 page=@page if page==-1
550 @links[link]=[page, y]
558 @links[link]=[page, y]
551 end
559 end
552
560
553 def Link(x, y, w, h, link)
561 def Link(x, y, w, h, link)
554 # Put a link on the page
562 # Put a link on the page
555 @PageLinks[@page]=Array.new unless @PageLinks.has_key?(@Page)
563 @PageLinks[@page]=Array.new unless @PageLinks.has_key?(@Page)
556 @PageLinks[@page].push([x*@k,@hPt-y*@k,w*@k,h*@k,link])
564 @PageLinks[@page].push([x*@k,@hPt-y*@k,w*@k,h*@k,link])
557 end
565 end
558
566
559 def Text(x, y, txt)
567 def Text(x, y, txt)
560 # Output a string
568 # Output a string
561 txt.gsub!(')', '\\)')
569 txt.gsub!(')', '\\)')
562 txt.gsub!('(', '\\(')
570 txt.gsub!('(', '\\(')
563 txt.gsub!('\\', '\\\\')
571 txt.gsub!('\\', '\\\\')
564 s=sprintf('BT %.2f %.2f Td (%s) Tj ET',x*@k,(@h-y)*@k,txt);
572 s=sprintf('BT %.2f %.2f Td (%s) Tj ET',x*@k,(@h-y)*@k,txt);
565 s=s+' '+dounderline(x,y,txt) if @underline and txt!=''
573 s=s+' '+dounderline(x,y,txt) if @underline and txt!=''
566 s='q '+@TextColor+' '+s+' Q' if @ColorFlag
574 s='q '+@TextColor+' '+s+' Q' if @ColorFlag
567 out(s)
575 out(s)
568 end
576 end
569
577
570 def AcceptPageBreak
578 def AcceptPageBreak
571 # Accept automatic page break or not
579 # Accept automatic page break or not
572 @AutoPageBreak
580 @AutoPageBreak
573 end
581 end
574
582
575 def Cell(w,h=0,txt='',border=0,ln=0,align='',fill=0,link='')
583 def Cell(w,h=0,txt='',border=0,ln=0,align='',fill=0,link='')
576 # Output a cell
584 # Output a cell
577 if @y+h>@PageBreakTrigger and !@InFooter and self.AcceptPageBreak
585 if @y+h>@PageBreakTrigger and !@InFooter and self.AcceptPageBreak
578 # Automatic page break
586 # Automatic page break
579 x=@x
587 x=@x
580 ws=@ws
588 ws=@ws
581 if ws>0
589 if ws>0
582 @ws=0
590 @ws=0
583 out('0 Tw')
591 out('0 Tw')
584 end
592 end
585 self.AddPage(@CurOrientation)
593 self.AddPage(@CurOrientation)
586 @x=x
594 @x=x
587 if ws>0
595 if ws>0
588 @ws=ws
596 @ws=ws
589 out(sprintf('%.3f Tw',ws*@k))
597 out(sprintf('%.3f Tw',ws*@k))
590 end
598 end
591 end
599 end
592 w=@w-@rMargin-@x if w==0
600 w=@w-@rMargin-@x if w==0
593 s=''
601 s=''
594 if fill==1 or border==1
602 if fill==1 or border==1
595 if fill==1
603 if fill==1
596 op=(border==1) ? 'B' : 'f'
604 op=(border==1) ? 'B' : 'f'
597 else
605 else
598 op='S'
606 op='S'
599 end
607 end
600 s=sprintf('%.2f %.2f %.2f %.2f re %s ',@x*@k,(@h-@y)*@k,w*@k,-h*@k,op)
608 s=sprintf('%.2f %.2f %.2f %.2f re %s ',@x*@k,(@h-@y)*@k,w*@k,-h*@k,op)
601 end
609 end
602 if border.is_a? String
610 if border.is_a? String
603 x=@x
611 x=@x
604 y=@y
612 y=@y
605 unless border.index('L').nil?
613 unless border.index('L').nil?
606 s=s+sprintf('%.2f %.2f m %.2f %.2f l S ',
614 s=s+sprintf('%.2f %.2f m %.2f %.2f l S ',
607 x*@k,(@h-y)*@k,x*@k,(@h-(y+h))*@k)
615 x*@k,(@h-y)*@k,x*@k,(@h-(y+h))*@k)
608 end
616 end
609 unless border.index('T').nil?
617 unless border.index('T').nil?
610 s=s+sprintf('%.2f %.2f m %.2f %.2f l S ',
618 s=s+sprintf('%.2f %.2f m %.2f %.2f l S ',
611 x*@k,(@h-y)*@k,(x+w)*@k,(@h-y)*@k)
619 x*@k,(@h-y)*@k,(x+w)*@k,(@h-y)*@k)
612 end
620 end
613 unless border.index('R').nil?
621 unless border.index('R').nil?
614 s=s+sprintf('%.2f %.2f m %.2f %.2f l S ',
622 s=s+sprintf('%.2f %.2f m %.2f %.2f l S ',
615 (x+w)*@k,(@h-y)*@k,(x+w)*@k,(@h-(y+h))*@k)
623 (x+w)*@k,(@h-y)*@k,(x+w)*@k,(@h-(y+h))*@k)
616 end
624 end
617 unless border.index('B').nil?
625 unless border.index('B').nil?
618 s=s+sprintf('%.2f %.2f m %.2f %.2f l S ',
626 s=s+sprintf('%.2f %.2f m %.2f %.2f l S ',
619 x*@k,(@h-(y+h))*@k,(x+w)*@k,(@h-(y+h))*@k)
627 x*@k,(@h-(y+h))*@k,(x+w)*@k,(@h-(y+h))*@k)
620 end
628 end
621 end
629 end
622 if txt!=''
630 if txt!=''
623 if align=='R'
631 if align=='R'
624 dx=w-@cMargin-self.GetStringWidth(txt)
632 dx=w-@cMargin-self.GetStringWidth(txt)
625 elsif align=='C'
633 elsif align=='C'
626 dx=(w-self.GetStringWidth(txt))/2
634 dx=(w-self.GetStringWidth(txt))/2
627 else
635 else
628 dx=@cMargin
636 dx=@cMargin
629 end
637 end
630 txt = txt.gsub(')', '\\)')
638 txt = txt.gsub(')', '\\)')
631 txt.gsub!('(', '\\(')
639 txt.gsub!('(', '\\(')
632 txt.gsub!('\\', '\\\\')
640 txt.gsub!('\\', '\\\\')
633 if @ColorFlag
641 if @ColorFlag
634 s=s+'q '+@TextColor+' '
642 s=s+'q '+@TextColor+' '
635 end
643 end
636 s=s+sprintf('BT %.2f %.2f Td (%s) Tj ET',
644 s=s+sprintf('BT %.2f %.2f Td (%s) Tj ET',
637 (@x+dx)*@k,(@h-(@y+0.5*h+0.3*@FontSize))*@k,txt)
645 (@x+dx)*@k,(@h-(@y+0.5*h+0.3*@FontSize))*@k,txt)
638 s=s+' '+dounderline(@x+dx,@y+0.5*h+0.3*@FontSize,txt) if @underline
646 s=s+' '+dounderline(@x+dx,@y+0.5*h+0.3*@FontSize,txt) if @underline
639 s=s+' Q' if @ColorFlag
647 s=s+' Q' if @ColorFlag
640 if link and link != ''
648 if link and link != ''
641 Link(@x+dx,@y+0.5*h-0.5*@FontSize,GetStringWidth(txt),@FontSize,link)
649 Link(@x+dx,@y+0.5*h-0.5*@FontSize,GetStringWidth(txt),@FontSize,link)
642 end
650 end
643 end
651 end
644 out(s) if s
652 out(s) if s
645 @lasth=h
653 @lasth=h
646 if ln>0
654 if ln>0
647 # Go to next line
655 # Go to next line
648 @y=@y+h
656 @y=@y+h
649 @x=@lMargin if ln==1
657 @x=@lMargin if ln==1
650 else
658 else
651 @x=@x+w
659 @x=@x+w
652 end
660 end
653 end
661 end
654
662
655 def MultiCell(w,h,txt,border=0,align='J',fill=0)
663 def MultiCell(w,h,txt,border=0,align='J',fill=0)
656 # Output text with automatic or explicit line breaks
664 # Output text with automatic or explicit line breaks
657 cw=@CurrentFont['cw']
665 cw=@CurrentFont['cw']
658 w=@w-@rMargin-@x if w==0
666 w=@w-@rMargin-@x if w==0
659 wmax=(w-2*@cMargin)*1000/@FontSize
667 wmax=(w-2*@cMargin)*1000/@FontSize
660 s=txt.gsub('\r','')
668 s=txt.gsub('\r','')
661 nb=s.length
669 nb=s.length
662 nb=nb-1 if nb>0 and s[nb-1].chr=='\n'
670 nb=nb-1 if nb>0 and s[nb-1].chr=='\n'
663 b=0
671 b=0
664 if border!=0
672 if border!=0
665 if border==1
673 if border==1
666 border='LTRB'
674 border='LTRB'
667 b='LRT'
675 b='LRT'
668 b2='LR'
676 b2='LR'
669 else
677 else
670 b2=''
678 b2=''
671 b2='L' unless border.index('L').nil?
679 b2='L' unless border.index('L').nil?
672 b2=b2+'R' unless border.index('R').nil?
680 b2=b2+'R' unless border.index('R').nil?
673 b=(not border.index('T').nil?) ? (b2+'T') : b2
681 b=(not border.index('T').nil?) ? (b2+'T') : b2
674 end
682 end
675 end
683 end
676 sep=-1
684 sep=-1
677 i=0
685 i=0
678 j=0
686 j=0
679 l=0
687 l=0
680 ns=0
688 ns=0
681 nl=1
689 nl=1
682 while i<nb
690 while i<nb
683 # Get next character
691 # Get next character
684 c=s[i].chr
692 c=s[i].chr
685 if c=="\n"
693 if c=="\n"
686 # Explicit line break
694 # Explicit line break
687 if @ws>0
695 if @ws>0
688 @ws=0
696 @ws=0
689 out('0 Tw')
697 out('0 Tw')
690 end
698 end
691 #Ed Moss
699 #Ed Moss
692 # Don't let i go negative
700 # Don't let i go negative
693 end_i = i == 0 ? 0 : i - 1
701 end_i = i == 0 ? 0 : i - 1
694 # Changed from s[j..i] to fix bug reported by Hans Allis.
702 # Changed from s[j..i] to fix bug reported by Hans Allis.
695 self.Cell(w,h,s[j..end_i],b,2,align,fill)
703 self.Cell(w,h,s[j..end_i],b,2,align,fill)
696 #
704 #
697 i=i+1
705 i=i+1
698 sep=-1
706 sep=-1
699 j=i
707 j=i
700 l=0
708 l=0
701 ns=0
709 ns=0
702 nl=nl+1
710 nl=nl+1
703 b=b2 if border and nl==2
711 b=b2 if border and nl==2
704 else
712 else
705 if c==' '
713 if c==' '
706 sep=i
714 sep=i
707 ls=l
715 ls=l
708 ns=ns+1
716 ns=ns+1
709 end
717 end
710 l=l+cw[c[0]]
718 l=l+GetCharWidth(cw, c[0])
711 if l>wmax
719 if l>wmax
712 # Automatic line break
720 # Automatic line break
713 if sep==-1
721 if sep==-1
714 i=i+1 if i==j
722 i=i+1 if i==j
715 if @ws>0
723 if @ws>0
716 @ws=0
724 @ws=0
717 out('0 Tw')
725 out('0 Tw')
718 end
726 end
719 self.Cell(w,h,s[j..i],b,2,align,fill)
727 self.Cell(w,h,s[j..i],b,2,align,fill)
720 #Ed Moss
728 #Ed Moss
721 # Added so that it wouldn't print the last character of the string if it got close
729 # Added so that it wouldn't print the last character of the string if it got close
722 #FIXME 2006-07-18 Level=0 - but it still puts out an extra new line
730 #FIXME 2006-07-18 Level=0 - but it still puts out an extra new line
723 i += 1
731 i += 1
724 #
732 #
725 else
733 else
726 if align=='J'
734 if align=='J'
727 @ws=(ns>1) ? (wmax-ls)/1000.0*@FontSize/(ns-1) : 0
735 @ws=(ns>1) ? (wmax-ls)/1000.0*@FontSize/(ns-1) : 0
728 out(sprintf('%.3f Tw',@ws*@k))
736 out(sprintf('%.3f Tw',@ws*@k))
729 end
737 end
730 self.Cell(w,h,s[j..sep],b,2,align,fill)
738 self.Cell(w,h,s[j..sep],b,2,align,fill)
731 i=sep+1
739 i=sep+1
732 end
740 end
733 sep=-1
741 sep=-1
734 j=i
742 j=i
735 l=0
743 l=0
736 ns=0
744 ns=0
737 nl=nl+1
745 nl=nl+1
738 b=b2 if border and nl==2
746 b=b2 if border and nl==2
739 else
747 else
740 i=i+1
748 i=i+1
741 end
749 end
742 end
750 end
743 end
751 end
744
752
745 # Last chunk
753 # Last chunk
746 if @ws>0
754 if @ws>0
747 @ws=0
755 @ws=0
748 out('0 Tw')
756 out('0 Tw')
749 end
757 end
750 b=b+'B' if border!=0 and not border.index('B').nil?
758 b=b+'B' if border!=0 and not border.index('B').nil?
751 self.Cell(w,h,s[j..i],b,2,align,fill)
759 self.Cell(w,h,s[j..i],b,2,align,fill)
752 @x=@lMargin
760 @x=@lMargin
753 end
761 end
754
762
755 def Write(h,txt,link='')
763 def Write(h,txt,link='')
756 # Output text in flowing mode
764 # Output text in flowing mode
757 cw=@CurrentFont['cw']
765 cw=@CurrentFont['cw']
758 w=@w-@rMargin-@x
766 w=@w-@rMargin-@x
759 wmax=(w-2*@cMargin)*1000/@FontSize
767 wmax=(w-2*@cMargin)*1000/@FontSize
760 s=txt.gsub("\r",'')
768 s=txt.gsub("\r",'')
761 nb=s.length
769 nb=s.length
762 sep=-1
770 sep=-1
763 i=0
771 i=0
764 j=0
772 j=0
765 l=0
773 l=0
766 nl=1
774 nl=1
767 while i<nb
775 while i<nb
768 # Get next character
776 # Get next character
769 c=s[i]
777 c=s[i]
770 if c=="\n"[0]
778 if c=="\n"[0]
771 # Explicit line break
779 # Explicit line break
772 self.Cell(w,h,s[j,i-j],0,2,'',0,link)
780 self.Cell(w,h,s[j,i-j],0,2,'',0,link)
773 i=i+1
781 i=i+1
774 sep=-1
782 sep=-1
775 j=i
783 j=i
776 l=0
784 l=0
777 if nl==1
785 if nl==1
778 @x=@lMargin
786 @x=@lMargin
779 w=@w-@rMargin-@x
787 w=@w-@rMargin-@x
780 wmax=(w-2*@cMargin)*1000/@FontSize
788 wmax=(w-2*@cMargin)*1000/@FontSize
781 end
789 end
782 nl=nl+1
790 nl=nl+1
783 next
791 next
784 end
792 end
785 if c==' '[0]
793 if c==' '[0]
786 sep=i
794 sep=i
787 ls=l
795 ls=l
788 end
796 end
789 l=l+cw[c];
797 l=l+GetCharWidth(cw, c);
790 if l>wmax
798 if l>wmax
791 # Automatic line break
799 # Automatic line break
792 if sep==-1
800 if sep==-1
793 if @x>@lMargin
801 if @x>@lMargin
794 # Move to next line
802 # Move to next line
795 @x=@lMargin
803 @x=@lMargin
796 @y=@y+h
804 @y=@y+h
797 w=@w-@rMargin-@x
805 w=@w-@rMargin-@x
798 wmax=(w-2*@cMargin)*1000/@FontSize
806 wmax=(w-2*@cMargin)*1000/@FontSize
799 i=i+1
807 i=i+1
800 nl=nl+1
808 nl=nl+1
801 next
809 next
802 end
810 end
803 i=i+1 if i==j
811 i=i+1 if i==j
804 self.Cell(w,h,s[j,i-j],0,2,'',0,link)
812 self.Cell(w,h,s[j,i-j],0,2,'',0,link)
805 else
813 else
806 self.Cell(w,h,s[j,sep-j],0,2,'',0,link)
814 self.Cell(w,h,s[j,sep-j],0,2,'',0,link)
807 i=sep+1
815 i=sep+1
808 end
816 end
809 sep=-1
817 sep=-1
810 j=i
818 j=i
811 l=0
819 l=0
812 if nl==1
820 if nl==1
813 @x=@lMargin
821 @x=@lMargin
814 w=@w-@rMargin-@x
822 w=@w-@rMargin-@x
815 wmax=(w-2*@cMargin)*1000/@FontSize
823 wmax=(w-2*@cMargin)*1000/@FontSize
816 end
824 end
817 nl=nl+1
825 nl=nl+1
818 else
826 else
819 i=i+1
827 i=i+1
820 end
828 end
821 end
829 end
822 # Last chunk
830 # Last chunk
823 self.Cell(l/1000.0*@FontSize,h,s[j,i],0,0,'',0,link) if i!=j
831 self.Cell(l/1000.0*@FontSize,h,s[j,i],0,0,'',0,link) if i!=j
824 end
832 end
825
833
826 def Image(file,x,y,w=0,h=0,type='',link='')
834 def Image(file,x,y,w=0,h=0,type='',link='')
827 # Put an image on the page
835 # Put an image on the page
828 unless @images.has_key?(file)
836 unless @images.has_key?(file)
829 # First use of image, get info
837 # First use of image, get info
830 if type==''
838 if type==''
831 pos=file.rindex('.')
839 pos=file.rindex('.')
832 if pos.nil?
840 if pos.nil?
833 self.Error('Image file has no extension and no type was '+
841 self.Error('Image file has no extension and no type was '+
834 'specified: '+file)
842 'specified: '+file)
835 end
843 end
836 type=file[pos+1..-1]
844 type=file[pos+1..-1]
837 end
845 end
838 type.downcase!
846 type.downcase!
839 if type=='jpg' or type=='jpeg'
847 if type=='jpg' or type=='jpeg'
840 info=parsejpg(file)
848 info=parsejpg(file)
841 elsif type=='png'
849 elsif type=='png'
842 info=parsepng(file)
850 info=parsepng(file)
843 else
851 else
844 self.Error('Unsupported image file type: '+type)
852 self.Error('Unsupported image file type: '+type)
845 end
853 end
846 info['i']=@images.length+1
854 info['i']=@images.length+1
847 @images[file]=info
855 @images[file]=info
848 else
856 else
849 info=@images[file]
857 info=@images[file]
850 end
858 end
851 #Ed Moss
859 #Ed Moss
852 if(w==0 && h==0)
860 if(w==0 && h==0)
853 #Put image at 72 dpi
861 #Put image at 72 dpi
854 w=info['w']/@k;
862 w=info['w']/@k;
855 h=info['h']/@k;
863 h=info['h']/@k;
856 end
864 end
857 #
865 #
858 # Automatic width or height calculation
866 # Automatic width or height calculation
859 w=h*info['w']/info['h'] if w==0
867 w=h*info['w']/info['h'] if w==0
860 h=w*info['h']/info['w'] if h==0
868 h=w*info['h']/info['w'] if h==0
861 out(sprintf('q %.2f 0 0 %.2f %.2f %.2f cm /I%d Do Q',
869 out(sprintf('q %.2f 0 0 %.2f %.2f %.2f cm /I%d Do Q',
862 w*@k,h*@k,x*@k,(@h-(y+h))*@k,info['i']))
870 w*@k,h*@k,x*@k,(@h-(y+h))*@k,info['i']))
863 Link(x,y,w,h,link) if link and link != ''
871 Link(x,y,w,h,link) if link and link != ''
864 end
872 end
865
873
866 def Ln(h='')
874 def Ln(h='')
867 # Line feed; default value is last cell height
875 # Line feed; default value is last cell height
868 @x=@lMargin
876 @x=@lMargin
869 if h.kind_of?(String)
877 if h.kind_of?(String)
870 @y=@y+@lasth
878 @y=@y+@lasth
871 else
879 else
872 @y=@y+h
880 @y=@y+h
873 end
881 end
874 end
882 end
875
883
876 def GetX
884 def GetX
877 # Get x position
885 # Get x position
878 @x
886 @x
879 end
887 end
880
888
881 def SetX(x)
889 def SetX(x)
882 # Set x position
890 # Set x position
883 if x>=0
891 if x>=0
884 @x=x
892 @x=x
885 else
893 else
886 @x=@w+x
894 @x=@w+x
887 end
895 end
888 end
896 end
889
897
890 def GetY
898 def GetY
891 # Get y position
899 # Get y position
892 @y
900 @y
893 end
901 end
894
902
895 def SetY(y)
903 def SetY(y)
896 # Set y position and reset x
904 # Set y position and reset x
897 @x=@lMargin
905 @x=@lMargin
898 if y>=0
906 if y>=0
899 @y=y
907 @y=y
900 else
908 else
901 @y=@h+y
909 @y=@h+y
902 end
910 end
903 end
911 end
904
912
905 def SetXY(x,y)
913 def SetXY(x,y)
906 # Set x and y positions
914 # Set x and y positions
907 SetY(y)
915 SetY(y)
908 SetX(x)
916 SetX(x)
909 end
917 end
910
918
911 def Output(file=nil)
919 def Output(file=nil)
912 # Output PDF to file or return as a string
920 # Output PDF to file or return as a string
913
921
914 # Finish document if necessary
922 # Finish document if necessary
915 self.Close if(@state<3)
923 self.Close if(@state<3)
916
924
917 if file.nil?
925 if file.nil?
918 # Return as a string
926 # Return as a string
919 return @buffer
927 return @buffer
920 else
928 else
921 # Save file locally
929 # Save file locally
922 open(file,'wb') do |f|
930 open(file,'wb') do |f|
923 f.write(@buffer)
931 f.write(@buffer)
924 end
932 end
925 end
933 end
926 end
934 end
927
935
928 private
936 private
929
937
930 def putpages
938 def putpages
931 nb=@page
939 nb=@page
932 unless @AliasNbPages.nil? or @AliasNbPages==''
940 unless @AliasNbPages.nil? or @AliasNbPages==''
933 # Replace number of pages
941 # Replace number of pages
934 1.upto(nb) do |n|
942 1.upto(nb) do |n|
935 @pages[n].gsub!(@AliasNbPages,nb.to_s)
943 @pages[n].gsub!(@AliasNbPages,nb.to_s)
936 end
944 end
937 end
945 end
938 if @DefOrientation=='P'
946 if @DefOrientation=='P'
939 wPt=@fwPt
947 wPt=@fwPt
940 hPt=@fhPt
948 hPt=@fhPt
941 else
949 else
942 wPt=@fhPt
950 wPt=@fhPt
943 hPt=@fwPt
951 hPt=@fwPt
944 end
952 end
945 filter=(@compress) ? '/Filter /FlateDecode ' : ''
953 filter=(@compress) ? '/Filter /FlateDecode ' : ''
946 1.upto(nb) do |n|
954 1.upto(nb) do |n|
947 # Page
955 # Page
948 newobj
956 newobj
949 out('<</Type /Page')
957 out('<</Type /Page')
950 out('/Parent 1 0 R')
958 out('/Parent 1 0 R')
951 unless @OrientationChanges[n].nil?
959 unless @OrientationChanges[n].nil?
952 out(sprintf('/MediaBox [0 0 %.2f %.2f]',hPt,wPt))
960 out(sprintf('/MediaBox [0 0 %.2f %.2f]',hPt,wPt))
953 end
961 end
954 out('/Resources 2 0 R')
962 out('/Resources 2 0 R')
955 if @PageLinks[n]
963 if @PageLinks[n]
956 # Links
964 # Links
957 annots='/Annots ['
965 annots='/Annots ['
958 @PageLinks[n].each do |pl|
966 @PageLinks[n].each do |pl|
959 rect=sprintf('%.2f %.2f %.2f %.2f',
967 rect=sprintf('%.2f %.2f %.2f %.2f',
960 pl[0],pl[1],pl[0]+pl[2],pl[1]-pl[3])
968 pl[0],pl[1],pl[0]+pl[2],pl[1]-pl[3])
961 annots=annots+'<</Type /Annot /Subtype /Link /Rect ['+rect+
969 annots=annots+'<</Type /Annot /Subtype /Link /Rect ['+rect+
962 '] /Border [0 0 0] '
970 '] /Border [0 0 0] '
963 if pl[4].kind_of?(String)
971 if pl[4].kind_of?(String)
964 annots=annots+'/A <</S /URI /URI '+textstring(pl[4])+
972 annots=annots+'/A <</S /URI /URI '+textstring(pl[4])+
965 '>>>>'
973 '>>>>'
966 else
974 else
967 l=@links[pl[4]]
975 l=@links[pl[4]]
968 h=@OrientationChanges[l[0]].nil? ? hPt : wPt
976 h=@OrientationChanges[l[0]].nil? ? hPt : wPt
969 annots=annots+sprintf(
977 annots=annots+sprintf(
970 '/Dest [%d 0 R /XYZ 0 %.2f null]>>',
978 '/Dest [%d 0 R /XYZ 0 %.2f null]>>',
971 1+2*l[0],h-l[1]*@k)
979 1+2*l[0],h-l[1]*@k)
972 end
980 end
973 end
981 end
974 out(annots+']')
982 out(annots+']')
975 end
983 end
976 out('/Contents '+(@n+1).to_s+' 0 R>>')
984 out('/Contents '+(@n+1).to_s+' 0 R>>')
977 out('endobj')
985 out('endobj')
978 # Page content
986 # Page content
979 p=(@compress) ? Zlib::Deflate.deflate(@pages[n]) : @pages[n]
987 p=(@compress) ? Zlib::Deflate.deflate(@pages[n]) : @pages[n]
980 newobj
988 newobj
981 out('<<'+filter+'/Length '+p.length.to_s+'>>')
989 out('<<'+filter+'/Length '+p.length.to_s+'>>')
982 putstream(p)
990 putstream(p)
983 out('endobj')
991 out('endobj')
984 end
992 end
985 # Pages root
993 # Pages root
986 @offsets[1]=@buffer.length
994 @offsets[1]=@buffer.length
987 out('1 0 obj')
995 out('1 0 obj')
988 out('<</Type /Pages')
996 out('<</Type /Pages')
989 kids='/Kids ['
997 kids='/Kids ['
990 nb.times do |i|
998 nb.times do |i|
991 kids=kids+(3+2*i).to_s+' 0 R '
999 kids=kids+(3+2*i).to_s+' 0 R '
992 end
1000 end
993 out(kids+']')
1001 out(kids+']')
994 out('/Count '+nb.to_s)
1002 out('/Count '+nb.to_s)
995 out(sprintf('/MediaBox [0 0 %.2f %.2f]',wPt,hPt))
1003 out(sprintf('/MediaBox [0 0 %.2f %.2f]',wPt,hPt))
996 out('>>')
1004 out('>>')
997 out('endobj')
1005 out('endobj')
998 end
1006 end
999
1007
1000 def putfonts
1008 def putfonts
1001 nf=@n
1009 nf=@n
1002 @diffs.each do |diff|
1010 @diffs.each do |diff|
1003 # Encodings
1011 # Encodings
1004 newobj
1012 newobj
1005 out('<</Type /Encoding /BaseEncoding /WinAnsiEncoding /Differences '+
1013 out('<</Type /Encoding /BaseEncoding /WinAnsiEncoding /Differences '+
1006 '['+diff+']>>')
1014 '['+diff+']>>')
1007 out('endobj')
1015 out('endobj')
1008 end
1016 end
1009
1017
1010 @FontFiles.each do |file, info|
1018 @FontFiles.each do |file, info|
1011 # Font file embedding
1019 # Font file embedding
1012 newobj
1020 newobj
1013 @FontFiles[file]['n'] = @n
1021 @FontFiles[file]['n'] = @n
1014
1022
1015 if self.class.const_defined? 'FPDF_FONTPATH' then
1023 if self.class.const_defined? 'FPDF_FONTPATH' then
1016 if FPDF_FONTPATH[-1,1] == '/' then
1024 if FPDF_FONTPATH[-1,1] == '/' then
1017 file = FPDF_FONTPATH + file
1025 file = FPDF_FONTPATH + file
1018 else
1026 else
1019 file = FPDF_FONTPATH + '/' + file
1027 file = FPDF_FONTPATH + '/' + file
1020 end
1028 end
1021 end
1029 end
1022
1030
1023 size = File.size(file)
1031 size = File.size(file)
1024 unless File.exists?(file)
1032 unless File.exists?(file)
1025 Error('Font file not found')
1033 Error('Font file not found')
1026 end
1034 end
1027
1035
1028 out('<</Length ' + size.to_s)
1036 out('<</Length ' + size.to_s)
1029
1037
1030 if file[-2, 2] == '.z' then
1038 if file[-2, 2] == '.z' then
1031 out('/Filter /FlateDecode')
1039 out('/Filter /FlateDecode')
1032 end
1040 end
1033 out('/Length1 ' + info['length1'])
1041 out('/Length1 ' + info['length1'])
1034 out('/Length2 ' + info['length2'] + ' /Length3 0') if info['length2']
1042 out('/Length2 ' + info['length2'] + ' /Length3 0') if info['length2']
1035 out('>>')
1043 out('>>')
1036 open(file, 'rb') do |f|
1044 open(file, 'rb') do |f|
1037 putstream(f.read())
1045 putstream(f.read())
1038 end
1046 end
1039 out('endobj')
1047 out('endobj')
1040 end
1048 end
1041
1049
1042 file = 0
1050 file = 0
1043 @fonts.each do |k, font|
1051 @fonts.each do |k, font|
1044 # Font objects
1052 # Font objects
1045 @fonts[k]['n']=@n+1
1053 @fonts[k]['n']=@n+1
1046 type=font['type']
1054 type=font['type']
1047 name=font['name']
1055 name=font['name']
1048 if type=='core'
1056 if type=='core'
1049 # Standard font
1057 # Standard font
1050 newobj
1058 newobj
1051 out('<</Type /Font')
1059 out('<</Type /Font')
1052 out('/BaseFont /'+name)
1060 out('/BaseFont /'+name)
1053 out('/Subtype /Type1')
1061 out('/Subtype /Type1')
1054 if name!='Symbol' and name!='ZapfDingbats'
1062 if name!='Symbol' and name!='ZapfDingbats'
1055 out('/Encoding /WinAnsiEncoding')
1063 out('/Encoding /WinAnsiEncoding')
1056 end
1064 end
1057 out('>>')
1065 out('>>')
1058 out('endobj')
1066 out('endobj')
1059 elsif type=='Type1' or type=='TrueType'
1067 elsif type=='Type1' or type=='TrueType'
1060 # Additional Type1 or TrueType font
1068 # Additional Type1 or TrueType font
1061 newobj
1069 newobj
1062 out('<</Type /Font')
1070 out('<</Type /Font')
1063 out('/BaseFont /'+name)
1071 out('/BaseFont /'+name)
1064 out('/Subtype /'+type)
1072 out('/Subtype /'+type)
1065 out('/FirstChar 32 /LastChar 255')
1073 out('/FirstChar 32 /LastChar 255')
1066 out('/Widths '+(@n+1).to_s+' 0 R')
1074 out('/Widths '+(@n+1).to_s+' 0 R')
1067 out('/FontDescriptor '+(@n+2).to_s+' 0 R')
1075 out('/FontDescriptor '+(@n+2).to_s+' 0 R')
1068 if font['enc'] and font['enc'] != ''
1076 if font['enc'] and font['enc'] != ''
1069 unless font['diff'].nil?
1077 unless font['diff'].nil?
1070 out('/Encoding '+(nf+font['diff']).to_s+' 0 R')
1078 out('/Encoding '+(nf+font['diff']).to_s+' 0 R')
1071 else
1079 else
1072 out('/Encoding /WinAnsiEncoding')
1080 out('/Encoding /WinAnsiEncoding')
1073 end
1081 end
1074 end
1082 end
1075 out('>>')
1083 out('>>')
1076 out('endobj')
1084 out('endobj')
1077 # Widths
1085 # Widths
1078 newobj
1086 newobj
1079 cw=font['cw']
1087 cw=font['cw']
1080 s='['
1088 s='['
1081 32.upto(255) do |i|
1089 32.upto(255) do |i|
1082 s << cw[i].to_s+' '
1090 s << GetCharWidth(cw, i).to_s + ' '
1083 end
1091 end
1084 out(s+']')
1092 out(s+']')
1085 out('endobj')
1093 out('endobj')
1086 # Descriptor
1094 # Descriptor
1087 newobj
1095 newobj
1088 s='<</Type /FontDescriptor /FontName /'+name
1096 s='<</Type /FontDescriptor /FontName /'+name
1089 font['desc'].each do |k, v|
1097 font['desc'].each do |k, v|
1090 s << ' /'+k+' '+v
1098 s << ' /'+k+' '+v
1091 end
1099 end
1092 file=font['file']
1100 file=font['file']
1093 if file
1101 if file
1094 s << ' /FontFile'+(type=='Type1' ? '' : '2')+' '+
1102 s << ' /FontFile'+(type=='Type1' ? '' : '2')+' '+
1095 @FontFiles[file]['n'].to_s+' 0 R'
1103 @FontFiles[file]['n'].to_s+' 0 R'
1096 end
1104 end
1097 out(s+'>>')
1105 out(s+'>>')
1098 out('endobj')
1106 out('endobj')
1099 else
1107 else
1100 # Allow for additional types
1108 # Allow for additional types
1101 mtd='put'+type.downcase
1109 mtd='put'+type.downcase
1102 unless self.respond_to?(mtd)
1110 unless self.respond_to?(mtd)
1103 self.Error('Unsupported font type: '+type)
1111 self.Error('Unsupported font type: '+type)
1104 end
1112 end
1105 self.send(mtd, font)
1113 self.send(mtd, font)
1106 end
1114 end
1107 end
1115 end
1108 end
1116 end
1109
1117
1110 def putimages
1118 def putimages
1111 filter=(@compress) ? '/Filter /FlateDecode ' : ''
1119 filter=(@compress) ? '/Filter /FlateDecode ' : ''
1112 @images.each do |file, info|
1120 @images.each do |file, info|
1113 newobj
1121 newobj
1114 @images[file]['n']=@n
1122 @images[file]['n']=@n
1115 out('<</Type /XObject')
1123 out('<</Type /XObject')
1116 out('/Subtype /Image')
1124 out('/Subtype /Image')
1117 out('/Width '+info['w'].to_s)
1125 out('/Width '+info['w'].to_s)
1118 out('/Height '+info['h'].to_s)
1126 out('/Height '+info['h'].to_s)
1119 if info['cs']=='Indexed'
1127 if info['cs']=='Indexed'
1120 out("/ColorSpace [/Indexed /DeviceRGB #{info['pal'].length/3-1} #{(@n+1)} 0 R]")
1128 out("/ColorSpace [/Indexed /DeviceRGB #{info['pal'].length/3-1} #{(@n+1)} 0 R]")
1121 else
1129 else
1122 out('/ColorSpace /'+info['cs'])
1130 out('/ColorSpace /'+info['cs'])
1123 if info['cs']=='DeviceCMYK'
1131 if info['cs']=='DeviceCMYK'
1124 out('/Decode [1 0 1 0 1 0 1 0]')
1132 out('/Decode [1 0 1 0 1 0 1 0]')
1125 end
1133 end
1126 end
1134 end
1127 out('/BitsPerComponent '+info['bpc'].to_s)
1135 out('/BitsPerComponent '+info['bpc'].to_s)
1128 out('/Filter /'+info['f']) if info['f']
1136 out('/Filter /'+info['f']) if info['f']
1129 unless info['parms'].nil?
1137 unless info['parms'].nil?
1130 out(info['parms'])
1138 out(info['parms'])
1131 end
1139 end
1132 if info['trns'] and info['trns'].kind_of?(Array)
1140 if info['trns'] and info['trns'].kind_of?(Array)
1133 trns=''
1141 trns=''
1134 info['trns'].length.times do |i|
1142 info['trns'].length.times do |i|
1135 trns=trns+info['trns'][i].to_s+' '+info['trns'][i].to_s+' '
1143 trns=trns+info['trns'][i].to_s+' '+info['trns'][i].to_s+' '
1136 end
1144 end
1137 out('/Mask ['+trns+']')
1145 out('/Mask ['+trns+']')
1138 end
1146 end
1139 out('/Length '+info['data'].length.to_s+'>>')
1147 out('/Length '+info['data'].length.to_s+'>>')
1140 putstream(info['data'])
1148 putstream(info['data'])
1141 @images[file]['data']=nil
1149 @images[file]['data']=nil
1142 out('endobj')
1150 out('endobj')
1143 # Palette
1151 # Palette
1144 if info['cs']=='Indexed'
1152 if info['cs']=='Indexed'
1145 newobj
1153 newobj
1146 pal=(@compress) ? Zlib::Deflate.deflate(info['pal']) : info['pal']
1154 pal=(@compress) ? Zlib::Deflate.deflate(info['pal']) : info['pal']
1147 out('<<'+filter+'/Length '+pal.length.to_s+'>>')
1155 out('<<'+filter+'/Length '+pal.length.to_s+'>>')
1148 putstream(pal)
1156 putstream(pal)
1149 out('endobj')
1157 out('endobj')
1150 end
1158 end
1151 end
1159 end
1152 end
1160 end
1153
1161
1154 def putxobjectdict
1162 def putxobjectdict
1155 @images.each_value do |image|
1163 @images.each_value do |image|
1156 out('/I'+image['i'].to_s+' '+image['n'].to_s+' 0 R')
1164 out('/I'+image['i'].to_s+' '+image['n'].to_s+' 0 R')
1157 end
1165 end
1158 end
1166 end
1159
1167
1160 def putresourcedict
1168 def putresourcedict
1161 out('/ProcSet [/PDF /Text /ImageB /ImageC /ImageI]')
1169 out('/ProcSet [/PDF /Text /ImageB /ImageC /ImageI]')
1162 out('/Font <<')
1170 out('/Font <<')
1163 @fonts.each_value do |font|
1171 @fonts.each_value do |font|
1164 out('/F'+font['i'].to_s+' '+font['n'].to_s+' 0 R')
1172 out('/F'+font['i'].to_s+' '+font['n'].to_s+' 0 R')
1165 end
1173 end
1166 out('>>')
1174 out('>>')
1167 out('/XObject <<')
1175 out('/XObject <<')
1168 putxobjectdict
1176 putxobjectdict
1169 out('>>')
1177 out('>>')
1170 end
1178 end
1171
1179
1172 def putresources
1180 def putresources
1173 putfonts
1181 putfonts
1174 putimages
1182 putimages
1175 # Resource dictionary
1183 # Resource dictionary
1176 @offsets[2]=@buffer.length
1184 @offsets[2]=@buffer.length
1177 out('2 0 obj')
1185 out('2 0 obj')
1178 out('<<')
1186 out('<<')
1179 putresourcedict
1187 putresourcedict
1180 out('>>')
1188 out('>>')
1181 out('endobj')
1189 out('endobj')
1182 end
1190 end
1183
1191
1184 def putinfo
1192 def putinfo
1185 out('/Producer '+textstring('Ruby FPDF '+FPDF_VERSION));
1193 out('/Producer '+textstring('Ruby FPDF '+FPDF_VERSION));
1186 unless @title.nil?
1194 unless @title.nil?
1187 out('/Title '+textstring(@title))
1195 out('/Title '+textstring(@title))
1188 end
1196 end
1189 unless @subject.nil?
1197 unless @subject.nil?
1190 out('/Subject '+textstring(@subject))
1198 out('/Subject '+textstring(@subject))
1191 end
1199 end
1192 unless @author.nil?
1200 unless @author.nil?
1193 out('/Author '+textstring(@author))
1201 out('/Author '+textstring(@author))
1194 end
1202 end
1195 unless @keywords.nil?
1203 unless @keywords.nil?
1196 out('/Keywords '+textstring(@keywords))
1204 out('/Keywords '+textstring(@keywords))
1197 end
1205 end
1198 unless @creator.nil?
1206 unless @creator.nil?
1199 out('/Creator '+textstring(@creator))
1207 out('/Creator '+textstring(@creator))
1200 end
1208 end
1201 out('/CreationDate '+textstring('D: '+DateTime.now.to_s))
1209 out('/CreationDate '+textstring('D: '+DateTime.now.to_s))
1202 end
1210 end
1203
1211
1204 def putcatalog
1212 def putcatalog
1205 out('/Type /Catalog')
1213 out('/Type /Catalog')
1206 out('/Pages 1 0 R')
1214 out('/Pages 1 0 R')
1207 if @ZoomMode=='fullpage'
1215 if @ZoomMode=='fullpage'
1208 out('/OpenAction [3 0 R /Fit]')
1216 out('/OpenAction [3 0 R /Fit]')
1209 elsif @ZoomMode=='fullwidth'
1217 elsif @ZoomMode=='fullwidth'
1210 out('/OpenAction [3 0 R /FitH null]')
1218 out('/OpenAction [3 0 R /FitH null]')
1211 elsif @ZoomMode=='real'
1219 elsif @ZoomMode=='real'
1212 out('/OpenAction [3 0 R /XYZ null null 1]')
1220 out('/OpenAction [3 0 R /XYZ null null 1]')
1213 elsif not @ZoomMode.kind_of?(String)
1221 elsif not @ZoomMode.kind_of?(String)
1214 out('/OpenAction [3 0 R /XYZ null null '+(@ZoomMode/100)+']')
1222 out('/OpenAction [3 0 R /XYZ null null '+(@ZoomMode/100)+']')
1215 end
1223 end
1216
1224
1217 if @LayoutMode=='single'
1225 if @LayoutMode=='single'
1218 out('/PageLayout /SinglePage')
1226 out('/PageLayout /SinglePage')
1219 elsif @LayoutMode=='continuous'
1227 elsif @LayoutMode=='continuous'
1220 out('/PageLayout /OneColumn')
1228 out('/PageLayout /OneColumn')
1221 elsif @LayoutMode=='two'
1229 elsif @LayoutMode=='two'
1222 out('/PageLayout /TwoColumnLeft')
1230 out('/PageLayout /TwoColumnLeft')
1223 end
1231 end
1224 end
1232 end
1225
1233
1226 def putheader
1234 def putheader
1227 out('%PDF-'+@PDFVersion)
1235 out('%PDF-'+@PDFVersion)
1228 end
1236 end
1229
1237
1230 def puttrailer
1238 def puttrailer
1231 out('/Size '+(@n+1).to_s)
1239 out('/Size '+(@n+1).to_s)
1232 out('/Root '+@n.to_s+' 0 R')
1240 out('/Root '+@n.to_s+' 0 R')
1233 out('/Info '+(@n-1).to_s+' 0 R')
1241 out('/Info '+(@n-1).to_s+' 0 R')
1234 end
1242 end
1235
1243
1236 def enddoc
1244 def enddoc
1237 putheader
1245 putheader
1238 putpages
1246 putpages
1239 putresources
1247 putresources
1240 # Info
1248 # Info
1241 newobj
1249 newobj
1242 out('<<')
1250 out('<<')
1243 putinfo
1251 putinfo
1244 out('>>')
1252 out('>>')
1245 out('endobj')
1253 out('endobj')
1246 # Catalog
1254 # Catalog
1247 newobj
1255 newobj
1248 out('<<')
1256 out('<<')
1249 putcatalog
1257 putcatalog
1250 out('>>')
1258 out('>>')
1251 out('endobj')
1259 out('endobj')
1252 # Cross-ref
1260 # Cross-ref
1253 o=@buffer.length
1261 o=@buffer.length
1254 out('xref')
1262 out('xref')
1255 out('0 '+(@n+1).to_s)
1263 out('0 '+(@n+1).to_s)
1256 out('0000000000 65535 f ')
1264 out('0000000000 65535 f ')
1257 1.upto(@n) do |i|
1265 1.upto(@n) do |i|
1258 out(sprintf('%010d 00000 n ',@offsets[i]))
1266 out(sprintf('%010d 00000 n ',@offsets[i]))
1259 end
1267 end
1260 # Trailer
1268 # Trailer
1261 out('trailer')
1269 out('trailer')
1262 out('<<')
1270 out('<<')
1263 puttrailer
1271 puttrailer
1264 out('>>')
1272 out('>>')
1265 out('startxref')
1273 out('startxref')
1266 out(o)
1274 out(o)
1267 out('%%EOF')
1275 out('%%EOF')
1268 state=3
1276 state=3
1269 end
1277 end
1270
1278
1271 def beginpage(orientation)
1279 def beginpage(orientation)
1272 @page=@page+1
1280 @page=@page+1
1273 @pages[@page]=''
1281 @pages[@page]=''
1274 @state=2
1282 @state=2
1275 @x=@lMargin
1283 @x=@lMargin
1276 @y=@tMargin
1284 @y=@tMargin
1277 @lasth=0
1285 @lasth=0
1278 @FontFamily=''
1286 @FontFamily=''
1279 # Page orientation
1287 # Page orientation
1280 if orientation==''
1288 if orientation==''
1281 orientation=@DefOrientation
1289 orientation=@DefOrientation
1282 else
1290 else
1283 orientation=orientation[0].chr.upcase
1291 orientation=orientation[0].chr.upcase
1284 if orientation!=@DefOrientation
1292 if orientation!=@DefOrientation
1285 @OrientationChanges[@page]=true
1293 @OrientationChanges[@page]=true
1286 end
1294 end
1287 end
1295 end
1288 if orientation!=@CurOrientation
1296 if orientation!=@CurOrientation
1289 # Change orientation
1297 # Change orientation
1290 if orientation=='P'
1298 if orientation=='P'
1291 @wPt=@fwPt
1299 @wPt=@fwPt
1292 @hPt=@fhPt
1300 @hPt=@fhPt
1293 @w=@fw
1301 @w=@fw
1294 @h=@fh
1302 @h=@fh
1295 else
1303 else
1296 @wPt=@fhPt
1304 @wPt=@fhPt
1297 @hPt=@fwPt
1305 @hPt=@fwPt
1298 @w=@fh
1306 @w=@fh
1299 @h=@fw
1307 @h=@fw
1300 end
1308 end
1301 @PageBreakTrigger=@h-@bMargin
1309 @PageBreakTrigger=@h-@bMargin
1302 @CurOrientation=orientation
1310 @CurOrientation=orientation
1303 end
1311 end
1304 end
1312 end
1305
1313
1306 def endpage
1314 def endpage
1307 # End of page contents
1315 # End of page contents
1308 @state=1
1316 @state=1
1309 end
1317 end
1310
1318
1311 def newobj
1319 def newobj
1312 # Begin a new object
1320 # Begin a new object
1313 @n=@n+1
1321 @n=@n+1
1314 @offsets[@n]=@buffer.length
1322 @offsets[@n]=@buffer.length
1315 out(@n.to_s+' 0 obj')
1323 out(@n.to_s+' 0 obj')
1316 end
1324 end
1317
1325
1318 def dounderline(x,y,txt)
1326 def dounderline(x,y,txt)
1319 # Underline text
1327 # Underline text
1320 up=@CurrentFont['up']
1328 up=@CurrentFont['up']
1321 ut=@CurrentFont['ut']
1329 ut=@CurrentFont['ut']
1322 w=GetStringWidth(txt)+@ws*txt.count(' ')
1330 w=GetStringWidth(txt)+@ws*txt.count(' ')
1323 sprintf('%.2f %.2f %.2f %.2f re f',
1331 sprintf('%.2f %.2f %.2f %.2f re f',
1324 x*@k,(@h-(y-up/1000.0*@FontSize))*@k,w*@k,-ut/1000.0*@FontSizePt)
1332 x*@k,(@h-(y-up/1000.0*@FontSize))*@k,w*@k,-ut/1000.0*@FontSizePt)
1325 end
1333 end
1326
1334
1327 def parsejpg(file)
1335 def parsejpg(file)
1328 # Extract info from a JPEG file
1336 # Extract info from a JPEG file
1329 a=extractjpginfo(file)
1337 a=extractjpginfo(file)
1330 raise "Missing or incorrect JPEG file: #{file}" if a.nil?
1338 raise "Missing or incorrect JPEG file: #{file}" if a.nil?
1331
1339
1332 if a['channels'].nil? || a['channels']==3 then
1340 if a['channels'].nil? || a['channels']==3 then
1333 colspace='DeviceRGB'
1341 colspace='DeviceRGB'
1334 elsif a['channels']==4 then
1342 elsif a['channels']==4 then
1335 colspace='DeviceCMYK'
1343 colspace='DeviceCMYK'
1336 else
1344 else
1337 colspace='DeviceGray'
1345 colspace='DeviceGray'
1338 end
1346 end
1339 bpc= a['bits'] ? a['bits'].to_i : 8
1347 bpc= a['bits'] ? a['bits'].to_i : 8
1340
1348
1341 # Read whole file
1349 # Read whole file
1342 data = nil
1350 data = nil
1343 open(file, 'rb') do |f|
1351 open(file, 'rb') do |f|
1344 data = f.read
1352 data = f.read
1345 end
1353 end
1346 return {'w'=>a['width'],'h'=>a['height'],'cs'=>colspace,'bpc'=>bpc,'f'=>'DCTDecode','data'=>data}
1354 return {'w'=>a['width'],'h'=>a['height'],'cs'=>colspace,'bpc'=>bpc,'f'=>'DCTDecode','data'=>data}
1347 end
1355 end
1348
1356
1349 def parsepng(file)
1357 def parsepng(file)
1350 # Extract info from a PNG file
1358 # Extract info from a PNG file
1351 f=open(file,'rb')
1359 f=open(file,'rb')
1352 # Check signature
1360 # Check signature
1353 unless f.read(8)==137.chr+'PNG'+13.chr+10.chr+26.chr+10.chr
1361 unless f.read(8)==137.chr+'PNG'+13.chr+10.chr+26.chr+10.chr
1354 self.Error('Not a PNG file: '+file)
1362 self.Error('Not a PNG file: '+file)
1355 end
1363 end
1356 # Read header chunk
1364 # Read header chunk
1357 f.read(4)
1365 f.read(4)
1358 if f.read(4)!='IHDR'
1366 if f.read(4)!='IHDR'
1359 self.Error('Incorrect PNG file: '+file)
1367 self.Error('Incorrect PNG file: '+file)
1360 end
1368 end
1361 w=freadint(f)
1369 w=freadint(f)
1362 h=freadint(f)
1370 h=freadint(f)
1363 bpc=f.read(1)[0]
1371 bpc=f.read(1)[0]
1364 if bpc>8
1372 if bpc>8
1365 self.Error('16-bit depth not supported: '+file)
1373 self.Error('16-bit depth not supported: '+file)
1366 end
1374 end
1367 ct=f.read(1)[0]
1375 ct=f.read(1)[0]
1368 if ct==0
1376 if ct==0
1369 colspace='DeviceGray'
1377 colspace='DeviceGray'
1370 elsif ct==2
1378 elsif ct==2
1371 colspace='DeviceRGB'
1379 colspace='DeviceRGB'
1372 elsif ct==3
1380 elsif ct==3
1373 colspace='Indexed'
1381 colspace='Indexed'
1374 else
1382 else
1375 self.Error('Alpha channel not supported: '+file)
1383 self.Error('Alpha channel not supported: '+file)
1376 end
1384 end
1377 if f.read(1)[0]!=0
1385 if f.read(1)[0]!=0
1378 self.Error('Unknown compression method: '+file)
1386 self.Error('Unknown compression method: '+file)
1379 end
1387 end
1380 if f.read(1)[0]!=0
1388 if f.read(1)[0]!=0
1381 self.Error('Unknown filter method: '+file)
1389 self.Error('Unknown filter method: '+file)
1382 end
1390 end
1383 if f.read(1)[0]!=0
1391 if f.read(1)[0]!=0
1384 self.Error('Interlacing not supported: '+file)
1392 self.Error('Interlacing not supported: '+file)
1385 end
1393 end
1386 f.read(4)
1394 f.read(4)
1387 parms='/DecodeParms <</Predictor 15 /Colors '+(ct==2 ? '3' : '1')+
1395 parms='/DecodeParms <</Predictor 15 /Colors '+(ct==2 ? '3' : '1')+
1388 ' /BitsPerComponent '+bpc.to_s+' /Columns '+w.to_s+'>>'
1396 ' /BitsPerComponent '+bpc.to_s+' /Columns '+w.to_s+'>>'
1389 # Scan chunks looking for palette, transparency and image data
1397 # Scan chunks looking for palette, transparency and image data
1390 pal=''
1398 pal=''
1391 trns=''
1399 trns=''
1392 data=''
1400 data=''
1393 begin
1401 begin
1394 n=freadint(f)
1402 n=freadint(f)
1395 type=f.read(4)
1403 type=f.read(4)
1396 if type=='PLTE'
1404 if type=='PLTE'
1397 # Read palette
1405 # Read palette
1398 pal=f.read(n)
1406 pal=f.read(n)
1399 f.read(4)
1407 f.read(4)
1400 elsif type=='tRNS'
1408 elsif type=='tRNS'
1401 # Read transparency info
1409 # Read transparency info
1402 t=f.read(n)
1410 t=f.read(n)
1403 if ct==0
1411 if ct==0
1404 trns=[t[1]]
1412 trns=[t[1]]
1405 elsif ct==2
1413 elsif ct==2
1406 trns=[t[1],t[3],t[5]]
1414 trns=[t[1],t[3],t[5]]
1407 else
1415 else
1408 pos=t.index(0)
1416 pos=t.index(0)
1409 trns=[pos] unless pos.nil?
1417 trns=[pos] unless pos.nil?
1410 end
1418 end
1411 f.read(4)
1419 f.read(4)
1412 elsif type=='IDAT'
1420 elsif type=='IDAT'
1413 # Read image data block
1421 # Read image data block
1414 data << f.read(n)
1422 data << f.read(n)
1415 f.read(4)
1423 f.read(4)
1416 elsif type=='IEND'
1424 elsif type=='IEND'
1417 break
1425 break
1418 else
1426 else
1419 f.read(n+4)
1427 f.read(n+4)
1420 end
1428 end
1421 end while n
1429 end while n
1422 if colspace=='Indexed' and pal==''
1430 if colspace=='Indexed' and pal==''
1423 self.Error('Missing palette in '+file)
1431 self.Error('Missing palette in '+file)
1424 end
1432 end
1425 f.close
1433 f.close
1426 {'w'=>w,'h'=>h,'cs'=>colspace,'bpc'=>bpc,'f'=>'FlateDecode',
1434 {'w'=>w,'h'=>h,'cs'=>colspace,'bpc'=>bpc,'f'=>'FlateDecode',
1427 'parms'=>parms,'pal'=>pal,'trns'=>trns,'data'=>data}
1435 'parms'=>parms,'pal'=>pal,'trns'=>trns,'data'=>data}
1428 end
1436 end
1429
1437
1430 def freadint(f)
1438 def freadint(f)
1431 # Read a 4-byte integer from file
1439 # Read a 4-byte integer from file
1432 a = f.read(4).unpack('N')
1440 a = f.read(4).unpack('N')
1433 return a[0]
1441 return a[0]
1434 end
1442 end
1435
1443
1436 def freadshort(f)
1444 def freadshort(f)
1437 a = f.read(2).unpack('n')
1445 a = f.read(2).unpack('n')
1438 return a[0]
1446 return a[0]
1439 end
1447 end
1440
1448
1441 def freadbyte(f)
1449 def freadbyte(f)
1442 a = f.read(1).unpack('C')
1450 a = f.read(1).unpack('C')
1443 return a[0]
1451 return a[0]
1444 end
1452 end
1445
1453
1446 def textstring(s)
1454 def textstring(s)
1447 # Format a text string
1455 # Format a text string
1448 '('+escape(s)+')'
1456 '('+escape(s)+')'
1449 end
1457 end
1450
1458
1451 def escape(s)
1459 def escape(s)
1452 # Add \ before \, ( and )
1460 # Add \ before \, ( and )
1453 s.gsub('\\','\\\\').gsub('(','\\(').gsub(')','\\)')
1461 s.gsub('\\','\\\\').gsub('(','\\(').gsub(')','\\)')
1454 end
1462 end
1455
1463
1456 def putstream(s)
1464 def putstream(s)
1457 out('stream')
1465 out('stream')
1458 out(s)
1466 out(s)
1459 out('endstream')
1467 out('endstream')
1460 end
1468 end
1461
1469
1462 def out(s)
1470 def out(s)
1463 # Add a line to the document
1471 # Add a line to the document
1464 if @state==2
1472 if @state==2
1465 @pages[@page]=@pages[@page]+s+"\n"
1473 @pages[@page]=@pages[@page]+s+"\n"
1466 else
1474 else
1467 @buffer=@buffer+s.to_s+"\n"
1475 @buffer=@buffer+s.to_s+"\n"
1468 end
1476 end
1469 end
1477 end
1470
1478
1471 # jpeg marker codes
1479 # jpeg marker codes
1472
1480
1473 M_SOF0 = 0xc0
1481 M_SOF0 = 0xc0
1474 M_SOF1 = 0xc1
1482 M_SOF1 = 0xc1
1475 M_SOF2 = 0xc2
1483 M_SOF2 = 0xc2
1476 M_SOF3 = 0xc3
1484 M_SOF3 = 0xc3
1477
1485
1478 M_SOF5 = 0xc5
1486 M_SOF5 = 0xc5
1479 M_SOF6 = 0xc6
1487 M_SOF6 = 0xc6
1480 M_SOF7 = 0xc7
1488 M_SOF7 = 0xc7
1481
1489
1482 M_SOF9 = 0xc9
1490 M_SOF9 = 0xc9
1483 M_SOF10 = 0xca
1491 M_SOF10 = 0xca
1484 M_SOF11 = 0xcb
1492 M_SOF11 = 0xcb
1485
1493
1486 M_SOF13 = 0xcd
1494 M_SOF13 = 0xcd
1487 M_SOF14 = 0xce
1495 M_SOF14 = 0xce
1488 M_SOF15 = 0xcf
1496 M_SOF15 = 0xcf
1489
1497
1490 M_SOI = 0xd8
1498 M_SOI = 0xd8
1491 M_EOI = 0xd9
1499 M_EOI = 0xd9
1492 M_SOS = 0xda
1500 M_SOS = 0xda
1493
1501
1494 def extractjpginfo(file)
1502 def extractjpginfo(file)
1495 result = nil
1503 result = nil
1496
1504
1497 open(file, "rb") do |f|
1505 open(file, "rb") do |f|
1498 marker = jpegnextmarker(f)
1506 marker = jpegnextmarker(f)
1499
1507
1500 if marker != M_SOI
1508 if marker != M_SOI
1501 return nil
1509 return nil
1502 end
1510 end
1503
1511
1504 while true
1512 while true
1505 marker = jpegnextmarker(f)
1513 marker = jpegnextmarker(f)
1506
1514
1507 case marker
1515 case marker
1508 when M_SOF0, M_SOF1, M_SOF2, M_SOF3,
1516 when M_SOF0, M_SOF1, M_SOF2, M_SOF3,
1509 M_SOF5, M_SOF6, M_SOF7, M_SOF9,
1517 M_SOF5, M_SOF6, M_SOF7, M_SOF9,
1510 M_SOF10, M_SOF11, M_SOF13, M_SOF14,
1518 M_SOF10, M_SOF11, M_SOF13, M_SOF14,
1511 M_SOF15 then
1519 M_SOF15 then
1512
1520
1513 length = freadshort(f)
1521 length = freadshort(f)
1514
1522
1515 if result.nil?
1523 if result.nil?
1516 result = {}
1524 result = {}
1517
1525
1518 result['bits'] = freadbyte(f)
1526 result['bits'] = freadbyte(f)
1519 result['height'] = freadshort(f)
1527 result['height'] = freadshort(f)
1520 result['width'] = freadshort(f)
1528 result['width'] = freadshort(f)
1521 result['channels'] = freadbyte(f)
1529 result['channels'] = freadbyte(f)
1522
1530
1523 f.seek(length - 8, IO::SEEK_CUR)
1531 f.seek(length - 8, IO::SEEK_CUR)
1524 else
1532 else
1525 f.seek(length - 2, IO::SEEK_CUR)
1533 f.seek(length - 2, IO::SEEK_CUR)
1526 end
1534 end
1527 when M_SOS, M_EOI then
1535 when M_SOS, M_EOI then
1528 return result
1536 return result
1529 else
1537 else
1530 length = freadshort(f)
1538 length = freadshort(f)
1531 f.seek(length - 2, IO::SEEK_CUR)
1539 f.seek(length - 2, IO::SEEK_CUR)
1532 end
1540 end
1533 end
1541 end
1534 end
1542 end
1535 end
1543 end
1536
1544
1537 def jpegnextmarker(f)
1545 def jpegnextmarker(f)
1538 while true
1546 while true
1539 # look for 0xff
1547 # look for 0xff
1540 while (c = freadbyte(f)) != 0xff
1548 while (c = freadbyte(f)) != 0xff
1541 end
1549 end
1542
1550
1543 c = freadbyte(f)
1551 c = freadbyte(f)
1544
1552
1545 if c != 0
1553 if c != 0
1546 return c
1554 return c
1547 end
1555 end
1548 end
1556 end
1549 end
1557 end
1550 end
1558 end
General Comments 0
You need to be logged in to leave comments. Login now