eventioz-pdf-writer 1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (86) hide show
  1. checksums.yaml +15 -0
  2. data/.gitignore +1 -0
  3. data/ChangeLog +113 -0
  4. data/Demo-README +43 -0
  5. data/Gemfile +4 -0
  6. data/LICENCE +131 -0
  7. data/README +33 -0
  8. data/Rakefile +1 -0
  9. data/Release-Announcement +87 -0
  10. data/bin/techbook +24 -0
  11. data/bugs/first_page_margins.rb +28 -0
  12. data/bugs/page_numbering_simple.rb +14 -0
  13. data/bugs/page_numbering_stop_and_start.rb +21 -0
  14. data/demo/chunkybacon.rb +36 -0
  15. data/demo/code.rb +71 -0
  16. data/demo/colornames.rb +47 -0
  17. data/demo/demo.rb +73 -0
  18. data/demo/gettysburg.rb +66 -0
  19. data/demo/hello.rb +26 -0
  20. data/demo/individual-i.rb +89 -0
  21. data/demo/pac.rb +70 -0
  22. data/demo/qr-language.rb +580 -0
  23. data/demo/qr-library.rb +380 -0
  24. data/images/bluesmoke.jpg +0 -0
  25. data/images/chunkybacon.jpg +0 -0
  26. data/images/chunkybacon.png +0 -0
  27. data/lib/pdf/charts.rb +13 -0
  28. data/lib/pdf/charts/stddev.rb +431 -0
  29. data/lib/pdf/core_ext/mutex.rb +11 -0
  30. data/lib/pdf/math.rb +108 -0
  31. data/lib/pdf/quickref.rb +333 -0
  32. data/lib/pdf/simpletable.rb +948 -0
  33. data/lib/pdf/techbook.rb +905 -0
  34. data/lib/pdf/writer.rb +2734 -0
  35. data/lib/pdf/writer/arc4.rb +63 -0
  36. data/lib/pdf/writer/fontmetrics.rb +203 -0
  37. data/lib/pdf/writer/fonts/Courier-Bold.afm +342 -0
  38. data/lib/pdf/writer/fonts/Courier-BoldOblique.afm +342 -0
  39. data/lib/pdf/writer/fonts/Courier-Oblique.afm +342 -0
  40. data/lib/pdf/writer/fonts/Courier.afm +342 -0
  41. data/lib/pdf/writer/fonts/Helvetica-Bold.afm +2827 -0
  42. data/lib/pdf/writer/fonts/Helvetica-BoldOblique.afm +2827 -0
  43. data/lib/pdf/writer/fonts/Helvetica-Oblique.afm +3051 -0
  44. data/lib/pdf/writer/fonts/Helvetica.afm +3051 -0
  45. data/lib/pdf/writer/fonts/MustRead.html +19 -0
  46. data/lib/pdf/writer/fonts/Symbol.afm +213 -0
  47. data/lib/pdf/writer/fonts/Times-Bold.afm +2588 -0
  48. data/lib/pdf/writer/fonts/Times-BoldItalic.afm +2384 -0
  49. data/lib/pdf/writer/fonts/Times-Italic.afm +2667 -0
  50. data/lib/pdf/writer/fonts/Times-Roman.afm +2419 -0
  51. data/lib/pdf/writer/fonts/ZapfDingbats.afm +225 -0
  52. data/lib/pdf/writer/graphics.rb +817 -0
  53. data/lib/pdf/writer/graphics/imageinfo.rb +365 -0
  54. data/lib/pdf/writer/lang.rb +43 -0
  55. data/lib/pdf/writer/lang/en.rb +99 -0
  56. data/lib/pdf/writer/object.rb +23 -0
  57. data/lib/pdf/writer/object/action.rb +35 -0
  58. data/lib/pdf/writer/object/annotation.rb +42 -0
  59. data/lib/pdf/writer/object/catalog.rb +39 -0
  60. data/lib/pdf/writer/object/contents.rb +70 -0
  61. data/lib/pdf/writer/object/destination.rb +40 -0
  62. data/lib/pdf/writer/object/encryption.rb +53 -0
  63. data/lib/pdf/writer/object/font.rb +72 -0
  64. data/lib/pdf/writer/object/fontdescriptor.rb +34 -0
  65. data/lib/pdf/writer/object/fontencoding.rb +40 -0
  66. data/lib/pdf/writer/object/image.rb +304 -0
  67. data/lib/pdf/writer/object/info.rb +51 -0
  68. data/lib/pdf/writer/object/outline.rb +30 -0
  69. data/lib/pdf/writer/object/outlines.rb +30 -0
  70. data/lib/pdf/writer/object/page.rb +195 -0
  71. data/lib/pdf/writer/object/pages.rb +115 -0
  72. data/lib/pdf/writer/object/procset.rb +46 -0
  73. data/lib/pdf/writer/object/viewerpreferences.rb +74 -0
  74. data/lib/pdf/writer/ohash.rb +58 -0
  75. data/lib/pdf/writer/oreader.rb +25 -0
  76. data/lib/pdf/writer/state.rb +48 -0
  77. data/lib/pdf/writer/strokestyle.rb +138 -0
  78. data/manual.pwd +5965 -0
  79. data/metaconfig +13 -0
  80. data/pdf-writer.gemspec +28 -0
  81. data/pre-setup.rb +56 -0
  82. data/setup.rb +1366 -0
  83. data/test/helper.rb +4 -0
  84. data/test/test_image_info.rb +16 -0
  85. data/test/test_page_numbering.rb +13 -0
  86. metadata +196 -0
@@ -0,0 +1,225 @@
1
+ StartFontMetrics 4.1
2
+ Comment Copyright (c) 1985, 1987, 1988, 1989, 1997 Adobe Systems Incorporated. All Rights Reserved.
3
+ Comment Creation Date: Thu May 1 15:14:13 1997
4
+ Comment UniqueID 43082
5
+ Comment VMusage 45775 55535
6
+ FontName ZapfDingbats
7
+ FullName ITC Zapf Dingbats
8
+ FamilyName ZapfDingbats
9
+ Weight Medium
10
+ ItalicAngle 0
11
+ IsFixedPitch false
12
+ CharacterSet Special
13
+ FontBBox -1 -143 981 820
14
+ UnderlinePosition -100
15
+ UnderlineThickness 50
16
+ Version 002.000
17
+ Notice Copyright (c) 1985, 1987, 1988, 1989, 1997 Adobe Systems Incorporated. All Rights Reserved.ITC Zapf Dingbats is a registered trademark of International Typeface Corporation.
18
+ EncodingScheme FontSpecific
19
+ StdHW 28
20
+ StdVW 90
21
+ StartCharMetrics 202
22
+ C 32 ; WX 278 ; N space ; B 0 0 0 0 ;
23
+ C 33 ; WX 974 ; N a1 ; B 35 72 939 621 ;
24
+ C 34 ; WX 961 ; N a2 ; B 35 81 927 611 ;
25
+ C 35 ; WX 974 ; N a202 ; B 35 72 939 621 ;
26
+ C 36 ; WX 980 ; N a3 ; B 35 0 945 692 ;
27
+ C 37 ; WX 719 ; N a4 ; B 34 139 685 566 ;
28
+ C 38 ; WX 789 ; N a5 ; B 35 -14 755 705 ;
29
+ C 39 ; WX 790 ; N a119 ; B 35 -14 755 705 ;
30
+ C 40 ; WX 791 ; N a118 ; B 35 -13 761 705 ;
31
+ C 41 ; WX 690 ; N a117 ; B 34 138 655 553 ;
32
+ C 42 ; WX 960 ; N a11 ; B 35 123 925 568 ;
33
+ C 43 ; WX 939 ; N a12 ; B 35 134 904 559 ;
34
+ C 44 ; WX 549 ; N a13 ; B 29 -11 516 705 ;
35
+ C 45 ; WX 855 ; N a14 ; B 34 59 820 632 ;
36
+ C 46 ; WX 911 ; N a15 ; B 35 50 876 642 ;
37
+ C 47 ; WX 933 ; N a16 ; B 35 139 899 550 ;
38
+ C 48 ; WX 911 ; N a105 ; B 35 50 876 642 ;
39
+ C 49 ; WX 945 ; N a17 ; B 35 139 909 553 ;
40
+ C 50 ; WX 974 ; N a18 ; B 35 104 938 587 ;
41
+ C 51 ; WX 755 ; N a19 ; B 34 -13 721 705 ;
42
+ C 52 ; WX 846 ; N a20 ; B 36 -14 811 705 ;
43
+ C 53 ; WX 762 ; N a21 ; B 35 0 727 692 ;
44
+ C 54 ; WX 761 ; N a22 ; B 35 0 727 692 ;
45
+ C 55 ; WX 571 ; N a23 ; B -1 -68 571 661 ;
46
+ C 56 ; WX 677 ; N a24 ; B 36 -13 642 705 ;
47
+ C 57 ; WX 763 ; N a25 ; B 35 0 728 692 ;
48
+ C 58 ; WX 760 ; N a26 ; B 35 0 726 692 ;
49
+ C 59 ; WX 759 ; N a27 ; B 35 0 725 692 ;
50
+ C 60 ; WX 754 ; N a28 ; B 35 0 720 692 ;
51
+ C 61 ; WX 494 ; N a6 ; B 35 0 460 692 ;
52
+ C 62 ; WX 552 ; N a7 ; B 35 0 517 692 ;
53
+ C 63 ; WX 537 ; N a8 ; B 35 0 503 692 ;
54
+ C 64 ; WX 577 ; N a9 ; B 35 96 542 596 ;
55
+ C 65 ; WX 692 ; N a10 ; B 35 -14 657 705 ;
56
+ C 66 ; WX 786 ; N a29 ; B 35 -14 751 705 ;
57
+ C 67 ; WX 788 ; N a30 ; B 35 -14 752 705 ;
58
+ C 68 ; WX 788 ; N a31 ; B 35 -14 753 705 ;
59
+ C 69 ; WX 790 ; N a32 ; B 35 -14 756 705 ;
60
+ C 70 ; WX 793 ; N a33 ; B 35 -13 759 705 ;
61
+ C 71 ; WX 794 ; N a34 ; B 35 -13 759 705 ;
62
+ C 72 ; WX 816 ; N a35 ; B 35 -14 782 705 ;
63
+ C 73 ; WX 823 ; N a36 ; B 35 -14 787 705 ;
64
+ C 74 ; WX 789 ; N a37 ; B 35 -14 754 705 ;
65
+ C 75 ; WX 841 ; N a38 ; B 35 -14 807 705 ;
66
+ C 76 ; WX 823 ; N a39 ; B 35 -14 789 705 ;
67
+ C 77 ; WX 833 ; N a40 ; B 35 -14 798 705 ;
68
+ C 78 ; WX 816 ; N a41 ; B 35 -13 782 705 ;
69
+ C 79 ; WX 831 ; N a42 ; B 35 -14 796 705 ;
70
+ C 80 ; WX 923 ; N a43 ; B 35 -14 888 705 ;
71
+ C 81 ; WX 744 ; N a44 ; B 35 0 710 692 ;
72
+ C 82 ; WX 723 ; N a45 ; B 35 0 688 692 ;
73
+ C 83 ; WX 749 ; N a46 ; B 35 0 714 692 ;
74
+ C 84 ; WX 790 ; N a47 ; B 34 -14 756 705 ;
75
+ C 85 ; WX 792 ; N a48 ; B 35 -14 758 705 ;
76
+ C 86 ; WX 695 ; N a49 ; B 35 -14 661 706 ;
77
+ C 87 ; WX 776 ; N a50 ; B 35 -6 741 699 ;
78
+ C 88 ; WX 768 ; N a51 ; B 35 -7 734 699 ;
79
+ C 89 ; WX 792 ; N a52 ; B 35 -14 757 705 ;
80
+ C 90 ; WX 759 ; N a53 ; B 35 0 725 692 ;
81
+ C 91 ; WX 707 ; N a54 ; B 35 -13 672 704 ;
82
+ C 92 ; WX 708 ; N a55 ; B 35 -14 672 705 ;
83
+ C 93 ; WX 682 ; N a56 ; B 35 -14 647 705 ;
84
+ C 94 ; WX 701 ; N a57 ; B 35 -14 666 705 ;
85
+ C 95 ; WX 826 ; N a58 ; B 35 -14 791 705 ;
86
+ C 96 ; WX 815 ; N a59 ; B 35 -14 780 705 ;
87
+ C 97 ; WX 789 ; N a60 ; B 35 -14 754 705 ;
88
+ C 98 ; WX 789 ; N a61 ; B 35 -14 754 705 ;
89
+ C 99 ; WX 707 ; N a62 ; B 34 -14 673 705 ;
90
+ C 100 ; WX 687 ; N a63 ; B 36 0 651 692 ;
91
+ C 101 ; WX 696 ; N a64 ; B 35 0 661 691 ;
92
+ C 102 ; WX 689 ; N a65 ; B 35 0 655 692 ;
93
+ C 103 ; WX 786 ; N a66 ; B 34 -14 751 705 ;
94
+ C 104 ; WX 787 ; N a67 ; B 35 -14 752 705 ;
95
+ C 105 ; WX 713 ; N a68 ; B 35 -14 678 705 ;
96
+ C 106 ; WX 791 ; N a69 ; B 35 -14 756 705 ;
97
+ C 107 ; WX 785 ; N a70 ; B 36 -14 751 705 ;
98
+ C 108 ; WX 791 ; N a71 ; B 35 -14 757 705 ;
99
+ C 109 ; WX 873 ; N a72 ; B 35 -14 838 705 ;
100
+ C 110 ; WX 761 ; N a73 ; B 35 0 726 692 ;
101
+ C 111 ; WX 762 ; N a74 ; B 35 0 727 692 ;
102
+ C 112 ; WX 762 ; N a203 ; B 35 0 727 692 ;
103
+ C 113 ; WX 759 ; N a75 ; B 35 0 725 692 ;
104
+ C 114 ; WX 759 ; N a204 ; B 35 0 725 692 ;
105
+ C 115 ; WX 892 ; N a76 ; B 35 0 858 705 ;
106
+ C 116 ; WX 892 ; N a77 ; B 35 -14 858 692 ;
107
+ C 117 ; WX 788 ; N a78 ; B 35 -14 754 705 ;
108
+ C 118 ; WX 784 ; N a79 ; B 35 -14 749 705 ;
109
+ C 119 ; WX 438 ; N a81 ; B 35 -14 403 705 ;
110
+ C 120 ; WX 138 ; N a82 ; B 35 0 104 692 ;
111
+ C 121 ; WX 277 ; N a83 ; B 35 0 242 692 ;
112
+ C 122 ; WX 415 ; N a84 ; B 35 0 380 692 ;
113
+ C 123 ; WX 392 ; N a97 ; B 35 263 357 705 ;
114
+ C 124 ; WX 392 ; N a98 ; B 34 263 357 705 ;
115
+ C 125 ; WX 668 ; N a99 ; B 35 263 633 705 ;
116
+ C 126 ; WX 668 ; N a100 ; B 36 263 634 705 ;
117
+ C 128 ; WX 390 ; N a89 ; B 35 -14 356 705 ;
118
+ C 129 ; WX 390 ; N a90 ; B 35 -14 355 705 ;
119
+ C 130 ; WX 317 ; N a93 ; B 35 0 283 692 ;
120
+ C 131 ; WX 317 ; N a94 ; B 35 0 283 692 ;
121
+ C 132 ; WX 276 ; N a91 ; B 35 0 242 692 ;
122
+ C 133 ; WX 276 ; N a92 ; B 35 0 242 692 ;
123
+ C 134 ; WX 509 ; N a205 ; B 35 0 475 692 ;
124
+ C 135 ; WX 509 ; N a85 ; B 35 0 475 692 ;
125
+ C 136 ; WX 410 ; N a206 ; B 35 0 375 692 ;
126
+ C 137 ; WX 410 ; N a86 ; B 35 0 375 692 ;
127
+ C 138 ; WX 234 ; N a87 ; B 35 -14 199 705 ;
128
+ C 139 ; WX 234 ; N a88 ; B 35 -14 199 705 ;
129
+ C 140 ; WX 334 ; N a95 ; B 35 0 299 692 ;
130
+ C 141 ; WX 334 ; N a96 ; B 35 0 299 692 ;
131
+ C 161 ; WX 732 ; N a101 ; B 35 -143 697 806 ;
132
+ C 162 ; WX 544 ; N a102 ; B 56 -14 488 706 ;
133
+ C 163 ; WX 544 ; N a103 ; B 34 -14 508 705 ;
134
+ C 164 ; WX 910 ; N a104 ; B 35 40 875 651 ;
135
+ C 165 ; WX 667 ; N a106 ; B 35 -14 633 705 ;
136
+ C 166 ; WX 760 ; N a107 ; B 35 -14 726 705 ;
137
+ C 167 ; WX 760 ; N a108 ; B 0 121 758 569 ;
138
+ C 168 ; WX 776 ; N a112 ; B 35 0 741 705 ;
139
+ C 169 ; WX 595 ; N a111 ; B 34 -14 560 705 ;
140
+ C 170 ; WX 694 ; N a110 ; B 35 -14 659 705 ;
141
+ C 171 ; WX 626 ; N a109 ; B 34 0 591 705 ;
142
+ C 172 ; WX 788 ; N a120 ; B 35 -14 754 705 ;
143
+ C 173 ; WX 788 ; N a121 ; B 35 -14 754 705 ;
144
+ C 174 ; WX 788 ; N a122 ; B 35 -14 754 705 ;
145
+ C 175 ; WX 788 ; N a123 ; B 35 -14 754 705 ;
146
+ C 176 ; WX 788 ; N a124 ; B 35 -14 754 705 ;
147
+ C 177 ; WX 788 ; N a125 ; B 35 -14 754 705 ;
148
+ C 178 ; WX 788 ; N a126 ; B 35 -14 754 705 ;
149
+ C 179 ; WX 788 ; N a127 ; B 35 -14 754 705 ;
150
+ C 180 ; WX 788 ; N a128 ; B 35 -14 754 705 ;
151
+ C 181 ; WX 788 ; N a129 ; B 35 -14 754 705 ;
152
+ C 182 ; WX 788 ; N a130 ; B 35 -14 754 705 ;
153
+ C 183 ; WX 788 ; N a131 ; B 35 -14 754 705 ;
154
+ C 184 ; WX 788 ; N a132 ; B 35 -14 754 705 ;
155
+ C 185 ; WX 788 ; N a133 ; B 35 -14 754 705 ;
156
+ C 186 ; WX 788 ; N a134 ; B 35 -14 754 705 ;
157
+ C 187 ; WX 788 ; N a135 ; B 35 -14 754 705 ;
158
+ C 188 ; WX 788 ; N a136 ; B 35 -14 754 705 ;
159
+ C 189 ; WX 788 ; N a137 ; B 35 -14 754 705 ;
160
+ C 190 ; WX 788 ; N a138 ; B 35 -14 754 705 ;
161
+ C 191 ; WX 788 ; N a139 ; B 35 -14 754 705 ;
162
+ C 192 ; WX 788 ; N a140 ; B 35 -14 754 705 ;
163
+ C 193 ; WX 788 ; N a141 ; B 35 -14 754 705 ;
164
+ C 194 ; WX 788 ; N a142 ; B 35 -14 754 705 ;
165
+ C 195 ; WX 788 ; N a143 ; B 35 -14 754 705 ;
166
+ C 196 ; WX 788 ; N a144 ; B 35 -14 754 705 ;
167
+ C 197 ; WX 788 ; N a145 ; B 35 -14 754 705 ;
168
+ C 198 ; WX 788 ; N a146 ; B 35 -14 754 705 ;
169
+ C 199 ; WX 788 ; N a147 ; B 35 -14 754 705 ;
170
+ C 200 ; WX 788 ; N a148 ; B 35 -14 754 705 ;
171
+ C 201 ; WX 788 ; N a149 ; B 35 -14 754 705 ;
172
+ C 202 ; WX 788 ; N a150 ; B 35 -14 754 705 ;
173
+ C 203 ; WX 788 ; N a151 ; B 35 -14 754 705 ;
174
+ C 204 ; WX 788 ; N a152 ; B 35 -14 754 705 ;
175
+ C 205 ; WX 788 ; N a153 ; B 35 -14 754 705 ;
176
+ C 206 ; WX 788 ; N a154 ; B 35 -14 754 705 ;
177
+ C 207 ; WX 788 ; N a155 ; B 35 -14 754 705 ;
178
+ C 208 ; WX 788 ; N a156 ; B 35 -14 754 705 ;
179
+ C 209 ; WX 788 ; N a157 ; B 35 -14 754 705 ;
180
+ C 210 ; WX 788 ; N a158 ; B 35 -14 754 705 ;
181
+ C 211 ; WX 788 ; N a159 ; B 35 -14 754 705 ;
182
+ C 212 ; WX 894 ; N a160 ; B 35 58 860 634 ;
183
+ C 213 ; WX 838 ; N a161 ; B 35 152 803 540 ;
184
+ C 214 ; WX 1016 ; N a163 ; B 34 152 981 540 ;
185
+ C 215 ; WX 458 ; N a164 ; B 35 -127 422 820 ;
186
+ C 216 ; WX 748 ; N a196 ; B 35 94 698 597 ;
187
+ C 217 ; WX 924 ; N a165 ; B 35 140 890 552 ;
188
+ C 218 ; WX 748 ; N a192 ; B 35 94 698 597 ;
189
+ C 219 ; WX 918 ; N a166 ; B 35 166 884 526 ;
190
+ C 220 ; WX 927 ; N a167 ; B 35 32 892 660 ;
191
+ C 221 ; WX 928 ; N a168 ; B 35 129 891 562 ;
192
+ C 222 ; WX 928 ; N a169 ; B 35 128 893 563 ;
193
+ C 223 ; WX 834 ; N a170 ; B 35 155 799 537 ;
194
+ C 224 ; WX 873 ; N a171 ; B 35 93 838 599 ;
195
+ C 225 ; WX 828 ; N a172 ; B 35 104 791 588 ;
196
+ C 226 ; WX 924 ; N a173 ; B 35 98 889 594 ;
197
+ C 227 ; WX 924 ; N a162 ; B 35 98 889 594 ;
198
+ C 228 ; WX 917 ; N a174 ; B 35 0 882 692 ;
199
+ C 229 ; WX 930 ; N a175 ; B 35 84 896 608 ;
200
+ C 230 ; WX 931 ; N a176 ; B 35 84 896 608 ;
201
+ C 231 ; WX 463 ; N a177 ; B 35 -99 429 791 ;
202
+ C 232 ; WX 883 ; N a178 ; B 35 71 848 623 ;
203
+ C 233 ; WX 836 ; N a179 ; B 35 44 802 648 ;
204
+ C 234 ; WX 836 ; N a193 ; B 35 44 802 648 ;
205
+ C 235 ; WX 867 ; N a180 ; B 35 101 832 591 ;
206
+ C 236 ; WX 867 ; N a199 ; B 35 101 832 591 ;
207
+ C 237 ; WX 696 ; N a181 ; B 35 44 661 648 ;
208
+ C 238 ; WX 696 ; N a200 ; B 35 44 661 648 ;
209
+ C 239 ; WX 874 ; N a182 ; B 35 77 840 619 ;
210
+ C 241 ; WX 874 ; N a201 ; B 35 73 840 615 ;
211
+ C 242 ; WX 760 ; N a183 ; B 35 0 725 692 ;
212
+ C 243 ; WX 946 ; N a184 ; B 35 160 911 533 ;
213
+ C 244 ; WX 771 ; N a197 ; B 34 37 736 655 ;
214
+ C 245 ; WX 865 ; N a185 ; B 35 207 830 481 ;
215
+ C 246 ; WX 771 ; N a194 ; B 34 37 736 655 ;
216
+ C 247 ; WX 888 ; N a198 ; B 34 -19 853 712 ;
217
+ C 248 ; WX 967 ; N a186 ; B 35 124 932 568 ;
218
+ C 249 ; WX 888 ; N a195 ; B 34 -19 853 712 ;
219
+ C 250 ; WX 831 ; N a187 ; B 35 113 796 579 ;
220
+ C 251 ; WX 873 ; N a188 ; B 36 118 838 578 ;
221
+ C 252 ; WX 927 ; N a189 ; B 35 150 891 542 ;
222
+ C 253 ; WX 970 ; N a190 ; B 35 76 931 616 ;
223
+ C 254 ; WX 918 ; N a191 ; B 34 99 884 593 ;
224
+ EndCharMetrics
225
+ EndFontMetrics
@@ -0,0 +1,817 @@
1
+ #--
2
+ # PDF::Writer for Ruby.
3
+ # http://rubyforge.org/projects/ruby-pdf/
4
+ # Copyright 2003 - 2005 Austin Ziegler.
5
+ #
6
+ # Licensed under a MIT-style licence. See LICENCE in the main distribution
7
+ # for full licensing information.
8
+ #
9
+ # $Id$
10
+ #++
11
+ # Points for use in the drawing of polygons.
12
+ class PDF::Writer::PolygonPoint
13
+ def initialize(x, y, connector = :line)
14
+ @x, @y, @connector = x, y, connector
15
+ end
16
+
17
+ attr_reader :x, :y, :connector
18
+ end
19
+
20
+ # This module contains graphics primitives. Objects that include this
21
+ # module must respond to #add_content.
22
+ #
23
+ # The PDF::Writer coordinate system is in PDF userspace units. The
24
+ # coordinate system in PDF::Writer is slightly different than might be
25
+ # expected, in that <tt>(0, 0)</tt> is at the lower left-hand corner of
26
+ # the canvas (page), not the normal top left-hand corner of the canvas.
27
+ # (See the diagram below.)
28
+ #
29
+ # Y Y
30
+ # 0+-----+X
31
+ # | |
32
+ # | |
33
+ # | |
34
+ # 0+-----+X
35
+ # 0 0
36
+ #
37
+ # Each primitive provided below indicates the <em>New Point</em>, or the
38
+ # coordinates new drawing point at the completion of the drawing
39
+ # operation. Drawing operations themselves do *not* draw or fill the path.
40
+ # This must be done by one of the stroke or fill operators, #stroke,
41
+ # #close_stroke, #fill, #close_fill, #fill_stroke, or #close_fill_stroke.
42
+ #
43
+ # Drawing operations return +self+ (the canvas) so that operations may be
44
+ # chained.
45
+ module PDF::Writer::Graphics
46
+ # Close the current path by appending a straight line segment from the
47
+ # drawing point to the starting point of the path. If the path is
48
+ # closed, this does nothing. This operator terminates the current
49
+ # subpath.
50
+ def close
51
+ add_content(" h")
52
+ self
53
+ end
54
+
55
+ # Stroke the path. This operation terminates a path object and draws it.
56
+ def stroke
57
+ add_content(" S")
58
+ self
59
+ end
60
+
61
+ # Close the current path by appending a straight line segment from the
62
+ # drawing point to the starting point of the path, and then stroke it.
63
+ # This does the same as #close followed by #stroke.
64
+ def close_stroke
65
+ add_content(" s")
66
+ self
67
+ end
68
+
69
+ # Fills the path. Open subpaths are implicitly closed before being
70
+ # filled. PDF offers two methods for determining the fill region. The
71
+ # first is called the "nonzero winding number" and is the default fill.
72
+ # The second is called "even-odd".
73
+ #
74
+ # Use the even-odd rule (called with <tt>#fill(:even_odd)</tt>) with
75
+ # caution, as this will cause certain portions of the path to be
76
+ # considered outside of the fill region, resulting in interesting cutout
77
+ # patterns.
78
+ def fill(rule = nil)
79
+ if :even_odd == rule
80
+ add_content(" f*")
81
+ else
82
+ add_content(" f")
83
+ end
84
+ self
85
+ end
86
+
87
+ # Close the current path by appending a straight line segment from the
88
+ # drawing point to the starting point of the path, and then fill it.
89
+ # This does the same as #close followed by #fill.
90
+ #
91
+ # See #fill for more information on fill rules.
92
+ def close_fill(rule = nil)
93
+ close
94
+ fill(rule)
95
+ self
96
+ end
97
+
98
+ # Fills and then strokes the path. Open subpaths are implicitly closed
99
+ # before being filled. This is the same as constructing two identical
100
+ # path objects, calling #fill on one and #stroke on the other. Paths
101
+ # filled and stroked in this manner are treated as if they were one
102
+ # object for PDF transparency purposes (the PDF transparency model is
103
+ # not yet supported by PDF::Writer).
104
+ #
105
+ # See #fill for more information on fill rules.
106
+ def fill_stroke(rule = nil)
107
+ if :even_odd == rule
108
+ add_content(" B*")
109
+ else
110
+ add_content(" B")
111
+ end
112
+ self
113
+ end
114
+
115
+ # Closes, fills and then strokes the path. Open subpaths are explicitly
116
+ # closed before being filled (as if #close and then #fill_stroke had
117
+ # been called). This is the same as constructing two identical path
118
+ # objects, calling #fill on one and #stroke on the other. Paths filled
119
+ # and stroked in this manner are treated as if they were one object for
120
+ # PDF transparency purposes (PDF transparency is not yet supported by
121
+ # PDF::Writer).
122
+ #
123
+ # See #fill for more information on fill rules.
124
+ def close_fill_stroke(rule = nil)
125
+ if :even_odd == rule
126
+ add_content(" b*")
127
+ else
128
+ add_content(" b")
129
+ end
130
+ self
131
+ end
132
+
133
+ # Move the drawing point to the specified coordinates <tt>(x, y)</tt>.
134
+ #
135
+ # New Point:: <tt>(x, y)</tt>
136
+ # Subpath:: New
137
+ def move_to(x, y)
138
+ add_content("\n%.3f %.3f m" % [ x, y ])
139
+ self
140
+ end
141
+
142
+ # Draw a straight line from the drawing point to <tt>(x, y)</tt>.
143
+ #
144
+ # New Point:: <tt>(x, y)</tt>
145
+ # Subpath:: Current
146
+ def line_to(x, y)
147
+ add_content("\n%.3f %.3f l" % [ x, y ])
148
+ self
149
+ end
150
+
151
+ # Draws a cubic Bezier curve from the drawing point to <tt>(x2, y2)</tt>
152
+ # using <tt>(x0, y0)</tt> and <tt>(x1, y1)</tt> as the control points
153
+ # for the curve.
154
+ #
155
+ # New Point:: <tt>(x2, y2)</tt>
156
+ # Subpath:: Current
157
+ def curve_to(x0, y0, x1, y1, x2, y2)
158
+ add_content("\n%.3f %.3f %.3f %.3f %.3f %.3f c" % [ x0, y0, x1, y1, x2, y2 ])
159
+ self
160
+ end
161
+
162
+ # Draws a cubic Bezier curve from the drawing point to <tt>(x1, y1)</tt>
163
+ # using the drawing point and <tt>(x0, y0)</tt> as the control points
164
+ # for the curve.
165
+ #
166
+ # New Point:: <tt>(x1, y1)</tt>
167
+ # Subpath:: Current
168
+ def scurve_to(x0, y0, x1, y1)
169
+ add_content("\n%.3f %.3f %.3f %.3f v" % [ x0, y0, x1, y1 ])
170
+ self
171
+ end
172
+
173
+ # Draws a cubic Bezier curve from the drawing point to <tt>(x1, y1)</tt>
174
+ # using <tt>(x0, y0)</tt> and <tt>(x1, y1)</tt> as the control points
175
+ # for the curve.
176
+ #
177
+ # New Point:: <tt>(x1, y1)</tt>
178
+ # Subpath:: Current
179
+ def ecurve_to(x0, y0, x1, y1)
180
+ add_content("\n%.3f %.3f %.3f %.3f y" % [ x0, y0, x1, y1 ])
181
+ self
182
+ end
183
+
184
+ # Draw a straight line from <tt>(x0, y0)</tt> to <tt>(x1, y1)</tt>. The
185
+ # line is a new subpath.
186
+ #
187
+ # New Point:: <tt>(x1, y1)</tt>.
188
+ # Subpath:: New
189
+ def line(x0, y0, x1, y1)
190
+ move_to(x0, y0).line_to(x1, y1)
191
+ end
192
+
193
+ # Draw a cubic Bezier curve from <tt>(x0, y0)</tt> to <tt>(x3, y3)</tt>
194
+ # using <tt>(x1, y1)</tt> and <tt>(x2, y2)</tt> as control points.
195
+ #
196
+ # New Point:: <tt>(x3, y3)</tt>
197
+ # Subpath:: New
198
+ def curve(x0, y0, x1, y1, x2, y2, x3, y3)
199
+ move_to(x0, y0).curve_to(x1, y1, x2, y2, x3, y3)
200
+ end
201
+
202
+ # Draw a cubic Bezier curve from <tt>(x0, y0)</tt> to <tt>(x2, y2)</tt>
203
+ # using <tt>(x0, y0)</tt> and <tt>(x1, y1)</tt> as control points.
204
+ #
205
+ # New Point:: <tt>(x2, y2)</tt>
206
+ # Subpath:: New
207
+ def scurve(x0, y0, x1, y1, x2, y2)
208
+ move_to(x0, y0).scurve_to(x1, y1, x2, y2)
209
+ end
210
+
211
+ # Draw a cubic Bezier curve from <tt>(x0, y0)</tt> to <tt>(x2, y2)</tt>
212
+ # using <tt>(x1, y1)</tt> and <tt>(x2, y2)</tt> as control points.
213
+ #
214
+ # New Point:: <tt>(x2, y2)</tt>
215
+ # Subpath:: New
216
+ def ecurve(x0, y0, x1, y1, x2, y2)
217
+ move_to(x0, y0).ecurve_to(x1, y1, x2, y2)
218
+ end
219
+
220
+ # This constant is used to approximate a symmetrical arc using a cubic
221
+ # Bezier curve.
222
+ KAPPA = 4.0 * ((Math.sqrt(2) - 1.0) / 3.0)
223
+
224
+ # Draws a circle of radius +r+ with the centre-point at <tt>(x, y)</tt>
225
+ # as a complete subpath. The drawing point will be moved to the
226
+ # centre-point upon completion of the drawing the circle.
227
+ def circle_at(x, y, r)
228
+ ellipse_at(x, y, r, r)
229
+ end
230
+
231
+ # Draws an ellipse of +x+ radius <tt>r1</tt> and +y+ radius <tt>r2</tt>
232
+ # with the centre-point at <tt>(x, y)</tt> as a complete subpath. The
233
+ # drawing point will be moved to the centre-point upon completion of the
234
+ # drawing the ellipse.
235
+ def ellipse_at(x, y, r1, r2 = r1)
236
+ l1 = r1 * KAPPA
237
+ l2 = r2 * KAPPA
238
+ move_to(x + r1, y)
239
+ # Upper right hand corner
240
+ curve_to(x + r1, y + l1, x + l2, y + r2, x, y + r2)
241
+ # Upper left hand corner
242
+ curve_to(x - l2, y + r2, x - r1, y + l1, x - r1, y)
243
+ # Lower left hand corner
244
+ curve_to(x - r1, y - l1, x - l2, y - r2, x, y - r2)
245
+ # Lower right hand corner
246
+ curve_to(x + l2, y - r2, x + r1, y - l1, x + r1, y)
247
+ move_to(x, y)
248
+ end
249
+
250
+ # Draw an ellipse centered at <tt>(x, y)</tt> with +x+ radius
251
+ # <tt>r1</tt> and +y+ radius <tt>r2</tt>. A partial ellipse can be drawn
252
+ # by specifying the starting and finishing angles.
253
+ #
254
+ # New Point:: <tt>(x, y)</tt>
255
+ # Subpath:: New
256
+ def ellipse2_at(x, y, r1, r2 = r1, start = 0, stop = 359.99, segments = 8)
257
+ segments = 2 if segments < 2
258
+
259
+ start = PDF::Math.deg2rad(start)
260
+ stop = PDF::Math.deg2rad(stop)
261
+
262
+ arc = stop - start
263
+ segarc = arc / segments.to_f
264
+ dtm = segarc / 3.0
265
+
266
+ theta = start
267
+ a0 = x + r1 * Math.cos(theta)
268
+ b0 = y + r2 * Math.sin(theta)
269
+ c0 = -r1 * Math.sin(theta)
270
+ d0 = r2 * Math.cos(theta)
271
+
272
+ move_to(a0, b0)
273
+
274
+ (1..segments).each do |ii|
275
+ theta = ii * segarc + start
276
+
277
+ a1 = x + r1 * Math.cos(theta)
278
+ b1 = y + r2 * Math.sin(theta)
279
+ c1 = -r1 * Math.sin(theta)
280
+ d1 = r2 * Math.cos(theta)
281
+
282
+ curve_to(a0 + (c0 * dtm),
283
+ b0 + (d0 * dtm),
284
+ a1 - (c1 * dtm),
285
+ b1 - (d1 * dtm), a1, b1)
286
+
287
+ a0 = a1
288
+ b0 = b1
289
+ c0 = c1
290
+ d0 = d1
291
+ end
292
+
293
+ move_to(x, y)
294
+ self
295
+ end
296
+
297
+ # Draws an ellipse segment. Draws a closed partial ellipse.
298
+ #
299
+ # New Point:: <tt>(x, y)</tt>
300
+ # Subpath:: New
301
+ def segment_at(x, y, r1, r2 = r1, start = 0, stop = 360, segments = 8)
302
+ ellipse2_at(x, y, r1, r2, start, stop, segments)
303
+
304
+ start = PDF::Math.deg2rad(start)
305
+ stop = PDF::Math.deg2rad(stop)
306
+
307
+ ax = x + r1 * Math.cos(start)
308
+ ay = y + r2 * Math.sin(start)
309
+ bx = x + r1 * Math.cos(stop)
310
+ by = y + r2 * Math.sin(stop)
311
+
312
+ move_to(ax, ay)
313
+ line_to(x, y)
314
+ line_to(bx, by)
315
+ move_to(x, y)
316
+ self
317
+ end
318
+
319
+ # Draw a polygon. +points+ is an array of PolygonPoint objects, or an
320
+ # array that can be converted to an array of PolygonPoint objects with
321
+ # <tt>PDF::Writer::PolygonPoint.new(*value)</tt>.
322
+ #
323
+ # New Point:: <tt>(points[-1].x, points[-1].y)</tt>
324
+ # Subpath:: New
325
+ def polygon(points)
326
+ points = points.map { |pp|
327
+ pp.kind_of?(Array) ? PDF::Writer::PolygonPoint.new(*pp) : pp
328
+ }
329
+
330
+ point = points.shift
331
+
332
+ move_to(point.x, point.y)
333
+
334
+ while not points.empty?
335
+ point = points.shift
336
+
337
+ case point.connector
338
+ when :curve
339
+ c1 = point
340
+ c2 = points.shift
341
+ point = points.shift
342
+
343
+ curve_to(c1.x, c1.y, c2.x, c2.y, point.x, point.y)
344
+ when :scurve
345
+ c1 = point
346
+ point = points.shift
347
+ scurve_to(c1.x, c1.y, point.x, point.y)
348
+ when :ecurve
349
+ c1 = point
350
+ point = points.shift
351
+ ecurve_to(c1.x, c1.y, point.x, point.y)
352
+ else
353
+ line_to(point.x, point.y)
354
+ end
355
+ end
356
+
357
+ self
358
+ end
359
+
360
+ # Draw a rectangle. The first corner is <tt>(x, y)</tt> and the second
361
+ # corner is <tt>(x + w, y - h)</tt>.
362
+ #
363
+ # New Point:: <tt>(x + w, y - h)</tt>
364
+ # Subpath:: Current
365
+ def rectangle(x, y, w, h = w)
366
+ add_content("\n%.3f %.3f %.3f %.3f re" % [ x, y, w, h ])
367
+ self
368
+ end
369
+
370
+ # Draw a rounded rectangle with corners <tt>(x, y)</tt> and <tt>(x + w,
371
+ # y - h)</tt> and corner radius +r+. The radius should be significantly
372
+ # smaller than +h+ and +w+.
373
+ #
374
+ # New Point:: <tt>(x + w, y - h)</tt>
375
+ # Subpath:: New
376
+ def rounded_rectangle(x, y, w, h, r)
377
+ x1 = x
378
+ x2 = x1 + w
379
+ y1 = y
380
+ y2 = y1 - h
381
+
382
+ r1 = r
383
+ r2 = r / 2.0
384
+
385
+ points = [
386
+ [ x1 + r1, y1, :line ],
387
+ [ x2 - r1, y1, :line ],
388
+ [ x2 - r2, y1, :curve ], # cp1
389
+ [ x2, y1 - r2, ], # cp2
390
+ [ x2, y1 - r1, ], # ep
391
+ [ x2, y2 + r1, :line ],
392
+ [ x2, y2 + r2, :curve ], # cp1
393
+ [ x2 - r2, y2, ], # cp2
394
+ [ x2 - r1, y2, ], # ep
395
+ [ x1 + r1, y2, :line ],
396
+ [ x1 + r2, y2, :curve ], # cp1
397
+ [ x1, y2 + r2, ], # cp2
398
+ [ x1, y2 + r1, ], # ep
399
+ [ x1, y1 - r1, :line ],
400
+ [ x1, y1 - r2, :curve ], # cp1
401
+ [ x1 + r2, y1, ], # cp2
402
+ [ x1 + r1, y1, ], # ep
403
+ ]
404
+ polygon(points)
405
+ move_to(x2, y2)
406
+ self
407
+ end
408
+
409
+ # Draws a star centered on <tt>(x, y)</tt> with +rays+ portions of
410
+ # +length+ from the centre. Stars with an odd number of rays should have
411
+ # the top ray pointing toward the top of the document. This will not
412
+ # create a "star" with fewer than four points.
413
+ #
414
+ # New Point:: <tt>(cx, cy)</tt>
415
+ # Subpath:: New
416
+ def star(cx, cy, length, rays = 5)
417
+ rays = 4 if rays < 4
418
+ points = []
419
+ part = Math::PI / rays.to_f
420
+
421
+ 0.step((rays * 4), 2) do |ray|
422
+ if ((ray / 2) % 2 == 0)
423
+ dist = length / 2.0
424
+ else
425
+ dist = length
426
+ end
427
+
428
+ x = cx + Math.cos((1.5 + ray / 2.0) * part) * dist
429
+ y = cy + Math.sin((1.5 + ray / 2.0) * part) * dist
430
+ points << [ x, y ]
431
+ end
432
+
433
+ polygon(points)
434
+ move_to(cx, cy)
435
+ self
436
+ end
437
+
438
+ # This sets the line drawing style. This *must* be a
439
+ # PDF::Writer::StrokeStyle object.
440
+ def stroke_style(style)
441
+ stroke_style!(style) if @current_stroke_style.nil? or style != @current_stroke_style
442
+ end
443
+
444
+ # Forces the line drawing style to be set, even if it's the same as the
445
+ # current color. Emits the current stroke style if +nil+ is provided.
446
+ def stroke_style!(style = nil)
447
+ @current_stroke_style = style if style
448
+ add_content "\n#{@current_stroke_style.render}" if @current_stroke_style
449
+ end
450
+
451
+ # Returns the current stroke style.
452
+ def stroke_style?
453
+ @current_stroke_style
454
+ end
455
+
456
+ # Set the text rendering style. This may be one of the following
457
+ # options:
458
+ #
459
+ # 0:: fill
460
+ # 1:: stroke
461
+ # 2:: fill then stroke
462
+ # 3:: invisible
463
+ # 4:: fill and add to clipping path
464
+ # 5:: stroke and add to clipping path
465
+ # 6:: fill and stroke and add to clipping path
466
+ # 7:: add to clipping path
467
+ def text_render_style(style)
468
+ text_render_style!(style) unless @current_text_render_style and style == @current_text_render_style
469
+ end
470
+
471
+ # Forces the text rendering style to be set, even if it's the same as
472
+ # the current style.
473
+ def text_render_style!(style)
474
+ @current_text_render_style = style
475
+ end
476
+
477
+ # Reutnrs the current text rendering style.
478
+ def text_render_style?
479
+ @current_text_render_style
480
+ end
481
+
482
+ # Sets the color for fill operations.
483
+ def fill_color(color)
484
+ fill_color!(color) if @current_fill_color.nil? or color != @current_fill_color
485
+ end
486
+
487
+ # Forces the color for fill operations to be set, even if the color
488
+ # is the same as the current color. Does nothing if +nil+ is provided.
489
+ def fill_color!(color = nil)
490
+ if color
491
+ @current_fill_color = color
492
+ add_content "\n#{@current_fill_color.pdf_fill}"
493
+ end
494
+ end
495
+
496
+ # Returns the current fill color.
497
+ def fill_color?
498
+ @current_fill_color
499
+ end
500
+
501
+ # Sets the color for stroke operations.
502
+ def stroke_color(color)
503
+ stroke_color!(color) if @current_stroke_color.nil? or color != @current_stroke_color
504
+ end
505
+
506
+ # Forces the color for stroke operations to be set, even if the color
507
+ # is the same as the current color. Does nothing if +nil+ is provided.
508
+ def stroke_color!(color = nil)
509
+ if color
510
+ @current_stroke_color = color
511
+ add_content "\n#{@current_stroke_color.pdf_stroke}"
512
+ end
513
+ end
514
+
515
+ # Returns the current stroke color.
516
+ def stroke_color?
517
+ @current_stroke_color
518
+ end
519
+
520
+ # Add an image from a file to the current page at position <tt>(x,
521
+ # y)</tt> (the lower left-hand corner of the image). The image will be
522
+ # scaled to +width+ by +height+ units. The image may be a PNG or JPEG
523
+ # image.
524
+ #
525
+ # The +image+ parameter may be a filename or an object that returns the
526
+ # full image data when #read is called with no parameters (such as an IO
527
+ # object). If 'open-uri' is loaded, then the image name may be an URI.
528
+ #
529
+ # In PDF::Writer 1.1 or later, the new +link+ parameter is a hash with
530
+ # two keys:
531
+ #
532
+ # <tt>:type</tt>:: The type of link, either <tt>:internal</tt> or
533
+ # <tt>:external</tt>.
534
+ # <tt>:target</tt>:: The destination of the link. For an
535
+ # <tt>:internal</tt> link, this is an internal
536
+ # cross-reference destination. For an
537
+ # <tt>:external</tt> link, this is an URI.
538
+ #
539
+ # This will automatically make the image a clickable link if set.
540
+ def add_image_from_file(image, x, y, width = nil, height = nil, link = nil)
541
+ data = nil
542
+
543
+ if image.respond_to?(:read)
544
+ data = image.read
545
+ else
546
+ if RUBY_VERSION >= '1.9'
547
+ open(image,'rb:binary') { |ff| data = ff.read }
548
+ else
549
+ open(image,'rb') { |ff| data = ff.read }
550
+ end
551
+ end
552
+
553
+ add_image(data, x, y, width, height, nil, link)
554
+ end
555
+
556
+ # Add an image from a loaded image (JPEG or PNG) resource at position
557
+ # <tt>(x, y)</tt> (the lower left-hand corner of the image) and scaled
558
+ # to +width+ by +height+ units. If provided, +image_info+ is a
559
+ # PDF::Writer::Graphics::ImageInfo object.
560
+ #
561
+ # In PDF::Writer 1.1 or later, the new +link+ parameter is a hash with
562
+ # two keys:
563
+ #
564
+ # <tt>:type</tt>:: The type of link, either <tt>:internal</tt> or
565
+ # <tt>:external</tt>.
566
+ # <tt>:target</tt>:: The destination of the link. For an
567
+ # <tt>:internal</tt> link, this is an internal
568
+ # cross-reference destination. For an
569
+ # <tt>:external</tt> link, this is an URI.
570
+ #
571
+ # This will automatically make the image a clickable link if set.
572
+ def add_image(image, x, y, width = nil, height = nil, image_info = nil, link = nil)
573
+ if image.kind_of?(PDF::Writer::External::Image)
574
+ label = image.label
575
+ image_obj = image
576
+ image_info ||= image.image_info
577
+ else
578
+ image_info ||= PDF::Writer::Graphics::ImageInfo.new(image)
579
+
580
+ tt = Time.now
581
+ @images << tt
582
+ id = @images.index(tt)
583
+ label = "I#{id}"
584
+ image_obj = PDF::Writer::External::Image.new(self, image, image_info, label)
585
+ @images[id] = image_obj
586
+ end
587
+
588
+ if width.nil? and height.nil?
589
+ width = image_info.width
590
+ height = image_info.height
591
+ end
592
+
593
+ width ||= height / image_info.height.to_f * image_info.width
594
+ height ||= width * image_info.height / image_info.width.to_f
595
+
596
+ tt = "\nq\n%.3f 0 0 %.3f %.3f %.3f cm\n/%s Do\nQ"
597
+ add_content(tt % [ width, height, x, y, label ])
598
+
599
+ if link
600
+ case link[:type]
601
+ when :internal
602
+ add_internal_link(link[:target], x, y, x + width, y + height)
603
+ when :external
604
+ add_link(link[:target], x, y, x + width, y + height)
605
+ end
606
+ end
607
+
608
+ image_obj
609
+ end
610
+
611
+ # Add an image easily to a PDF document. +image+ is the name of a JPG or
612
+ # PNG image. +options+ is a Hash:
613
+ #
614
+ # <tt>:pad</tt>:: The number of PDF userspace units that will
615
+ # be on all sides of the image. The default is
616
+ # <tt>5</tt> units.
617
+ # <tt>:width</tt>:: The desired width of the image. The image
618
+ # will be resized to this width with the
619
+ # aspect ratio kept. If unspecified, the
620
+ # image's natural width will be used.
621
+ # <tt>:resize</tt>:: How to resize the image, either :width
622
+ # (resizes the image to be as wide as the
623
+ # margins) or :full (resizes the image to be
624
+ # as large as possible). May be a numeric
625
+ # value, used as a multiplier for the image
626
+ # size (e.g., 0.5 will shrink the image to
627
+ # half-sized). If this and <tt>:width</tt> are
628
+ # unspecified, the image's natural size will be
629
+ # used. Mutually exclusive with the
630
+ # <tt>:width<tt> option.
631
+ # <tt>:justification</tt>:: The placement of the image. May be :center,
632
+ # :right, or :left. Defaults to :left.
633
+ # <tt>:border</tt>:: The border options. No default border. If
634
+ # specified, must be either +true+, which uses
635
+ # the default border, or a Hash.
636
+ # <tt>:link</tt>:: Makes the image a clickable link.
637
+ #
638
+ # Image borders are specified as a hash with two options:
639
+ #
640
+ # <tt>:color</tt>:: The colour of the border. Defaults to 50% grey.
641
+ # <tt>:style</tt>:: The stroke style of the border. This must be a
642
+ # StrokeStyle object and defaults to the default line.
643
+ #
644
+ # Image links are defined as a hash with two options:
645
+ #
646
+ # <tt>:type</tt>:: The type of link, either <tt>:internal</tt> or
647
+ # <tt>:external</tt>.
648
+ # <tt>:target</tt>:: The destination of the link. For an
649
+ # <tt>:internal</tt> link, this is an internal
650
+ # cross-reference destination. For an
651
+ # <tt>:external</tt> link, this is an URI.
652
+ def image(image, options = {})
653
+ width = options[:width]
654
+ pad = options[:pad] || 5
655
+ resize = options[:resize]
656
+ just = options[:justification] || :left
657
+ border = options[:border]
658
+ link = options[:link]
659
+
660
+ if image.kind_of?(PDF::Writer::External::Image)
661
+ info = image.image_info
662
+ image_data = image
663
+ else
664
+ if image.respond_to?(:read)
665
+ image_data = image.read
666
+ else
667
+ image_data = open(image, "rb") { |file| file.read }
668
+ end
669
+ info = PDF::Writer::Graphics::ImageInfo.new(image_data)
670
+ end
671
+
672
+ raise "Unsupported Image Type" unless %w(JPEG PNG).include?(info.format)
673
+
674
+ width = info.width if width.nil?
675
+ aspect = info.width.to_f / info.height.to_f
676
+
677
+ # Get the maximum width of the image on insertion.
678
+ if @columns_on
679
+ max_width = @columns[:width] - (pad * 2)
680
+ else
681
+ max_width = @page_width - (pad * 2) - @left_margin - @right_margin
682
+ end
683
+
684
+ if resize == :full or resize == :width or width > max_width
685
+ width = max_width
686
+ end
687
+
688
+ # Keep the height in an appropriate aspect ratio of the width.
689
+ height = (width / aspect.to_f)
690
+
691
+ # Resize the image.
692
+ if resize.kind_of?(Numeric)
693
+ width *= resize
694
+ height *= resize
695
+ end
696
+
697
+ # Resize the image *again*, if it is wider than what is available.
698
+ if width > max_width
699
+ height = (width / aspect.to_f)
700
+ end
701
+
702
+ # If the height is greater than the available space:
703
+ havail = @y - @bottom_margin - (pad * 2)
704
+ if height > havail
705
+ # If the image is to be resized to :full (remaining space
706
+ # available), adjust the image size appropriately. Otherwise, start
707
+ # a new page and flow to the next page.
708
+ if resize == :full
709
+ height = havail
710
+ width = (height * aspect)
711
+ else
712
+ start_new_page
713
+ end
714
+ end
715
+
716
+ # Find the x and y positions.
717
+ y = @y - pad - height
718
+ x = @left_margin + pad
719
+
720
+ if (width < max_width)
721
+ case just
722
+ when :center
723
+ x += (max_width - width) / 2.0
724
+ when :right
725
+ x += (max_width - width)
726
+ end
727
+ end
728
+
729
+ image_obj = add_image(image_data, x, y, width, height, info)
730
+
731
+ if border
732
+ border = {} if true == border
733
+ border[:color] ||= Color::RGB::Grey50
734
+ border[:style] ||= PDF::Writer::StrokeStyle::DEFAULT
735
+
736
+ save_state
737
+ stroke_color border[:color]
738
+ stroke_style border[:style]
739
+ rectangle(x, y - pad, width, height - pad).stroke
740
+ restore_state
741
+ end
742
+
743
+ if link
744
+ case link[:type]
745
+ when :internal
746
+ add_internal_link(link[:target], x, y - pad, x + width, y + height - pad)
747
+ when :external
748
+ add_link(link[:target], x, y - pad, x + width, y + height - pad)
749
+ end
750
+ end
751
+
752
+ @y = @y - pad - height
753
+
754
+ image_obj
755
+ end
756
+
757
+ # Translate the coordinate system axis by the specified user space
758
+ # coordinates.
759
+ def translate_axis(x, y)
760
+ add_content("\n1 0 0 1 %.3f %.3f cm" % [ x, y ])
761
+ self
762
+ end
763
+
764
+ # Rotate the axis of the coordinate system by the specified clockwise
765
+ # angle.
766
+ def rotate_axis(angle)
767
+ rad = PDF::Math.deg2rad(angle)
768
+ tt = "\n%.3f %.3f %.3f %.3f 0 0 cm"
769
+ tx = [ Math.cos(rad), Math.sin(rad), -Math.sin(rad), Math.cos(rad) ]
770
+ add_content(tt % tx)
771
+ self
772
+ end
773
+
774
+ # Scale the coordinate system axis by the specified factors.
775
+ def scale_axis(x = 1, y = 1)
776
+ add_content("\n%.3f 0 0 %.3f 0 0 cm" % [ x, y ])
777
+ self
778
+ end
779
+
780
+ # Skew the coordinate system axis by the specified angles.
781
+ def skew_axis(xangle = 0, yangle = 0)
782
+ xr = PDF::Math.deg2rad(xangle)
783
+ yr = PDF::Math.deg2rad(yangle)
784
+
785
+ xr = Math.tan(xr) if xangle != 0
786
+ yr = Math.tan(yr) if yangle != 0
787
+
788
+ add_content("\n1 %.3f %.3f 1 0 0 cm" % [ xr, yr ])
789
+ self
790
+ end
791
+
792
+ # Transforms the coordinate axis with the appended matrix. All
793
+ # transformations (including those above) are performed with this
794
+ # matrix. The transformation matrix is:
795
+ #
796
+ # +- -+
797
+ # | a c e |
798
+ # | b d f |
799
+ # | 0 0 1 |
800
+ # +- -+
801
+ #
802
+ # The six values are represented as a six-digit vector: [ a b c d e f ]
803
+ #
804
+ # * Axis translation uses [ 1 0 0 1 x y ] where x and y are the new
805
+ # (0,0) coordinates in the old axis system.
806
+ # * Scaling uses [ sx 0 0 sy 0 0 ] where sx and sy are the scaling
807
+ # factors.
808
+ # * Rotation uses [ cos(a) sin(a) -sin(a) cos(a) 0 0 ] where a is the
809
+ # angle, measured in radians.
810
+ # * X axis skewing uses [ 1 0 tan(a) 1 0 0 ] where a is the angle,
811
+ # measured in radians.
812
+ # * Y axis skewing uses [ 1 tan(a) 0 1 0 0 ] where a is the angle,
813
+ # measured in radians.
814
+ def transform_matrix(a, b, c, d, e, f)
815
+ add_content("\n%.3f %.3f %.3f %.3f %.3f %.3f cm" % [ a, b, c, d, e, f ])
816
+ end
817
+ end