prawn 0.4.1 → 0.5.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (179) hide show
  1. data/lib/prawn.rb +2 -72
  2. metadata +33 -224
  3. data/COPYING +0 -340
  4. data/LICENSE +0 -56
  5. data/README +0 -40
  6. data/Rakefile +0 -79
  7. data/data/encodings/win_ansi.txt +0 -29
  8. data/data/fonts/Action Man.dfont +0 -0
  9. data/data/fonts/Activa.ttf +0 -0
  10. data/data/fonts/Chalkboard.ttf +0 -0
  11. data/data/fonts/Courier-Bold.afm +0 -342
  12. data/data/fonts/Courier-BoldOblique.afm +0 -342
  13. data/data/fonts/Courier-Oblique.afm +0 -342
  14. data/data/fonts/Courier.afm +0 -342
  15. data/data/fonts/DejaVuSans.ttf +0 -0
  16. data/data/fonts/Dustismo_Roman.ttf +0 -0
  17. data/data/fonts/Helvetica-Bold.afm +0 -2827
  18. data/data/fonts/Helvetica-BoldOblique.afm +0 -2827
  19. data/data/fonts/Helvetica-Oblique.afm +0 -3051
  20. data/data/fonts/Helvetica.afm +0 -3051
  21. data/data/fonts/MustRead.html +0 -19
  22. data/data/fonts/Symbol.afm +0 -213
  23. data/data/fonts/Times-Bold.afm +0 -2588
  24. data/data/fonts/Times-BoldItalic.afm +0 -2384
  25. data/data/fonts/Times-Italic.afm +0 -2667
  26. data/data/fonts/Times-Roman.afm +0 -2419
  27. data/data/fonts/ZapfDingbats.afm +0 -225
  28. data/data/fonts/comicsans.ttf +0 -0
  29. data/data/fonts/gkai00mp.ttf +0 -0
  30. data/data/images/arrow.png +0 -0
  31. data/data/images/arrow2.png +0 -0
  32. data/data/images/barcode_issue.png +0 -0
  33. data/data/images/dice.alpha +0 -0
  34. data/data/images/dice.dat +0 -0
  35. data/data/images/dice.png +0 -0
  36. data/data/images/fractal.jpg +0 -0
  37. data/data/images/letterhead.jpg +0 -0
  38. data/data/images/page_white_text.alpha +0 -0
  39. data/data/images/page_white_text.dat +0 -0
  40. data/data/images/page_white_text.png +0 -0
  41. data/data/images/pigs.jpg +0 -0
  42. data/data/images/rails.dat +0 -0
  43. data/data/images/rails.png +0 -0
  44. data/data/images/ruport.png +0 -0
  45. data/data/images/ruport_data.dat +0 -0
  46. data/data/images/ruport_transparent.png +0 -0
  47. data/data/images/ruport_type0.png +0 -0
  48. data/data/images/stef.jpg +0 -0
  49. data/data/images/web-links.dat +0 -1
  50. data/data/images/web-links.png +0 -0
  51. data/data/shift_jis_text.txt +0 -1
  52. data/examples/bounding_box/bounding_boxes.rb +0 -44
  53. data/examples/bounding_box/lazy_bounding_boxes.rb +0 -28
  54. data/examples/bounding_box/padded_box.rb +0 -24
  55. data/examples/bounding_box/russian_boxes.rb +0 -37
  56. data/examples/general/background.rb +0 -20
  57. data/examples/general/canvas.rb +0 -16
  58. data/examples/general/measurement_units.rb +0 -52
  59. data/examples/general/multi_page_layout.rb +0 -17
  60. data/examples/general/page_geometry.rb +0 -32
  61. data/examples/graphics/basic_images.rb +0 -27
  62. data/examples/graphics/cmyk.rb +0 -13
  63. data/examples/graphics/curves.rb +0 -12
  64. data/examples/graphics/hexagon.rb +0 -14
  65. data/examples/graphics/image_fit.rb +0 -16
  66. data/examples/graphics/image_flow.rb +0 -38
  67. data/examples/graphics/image_position.rb +0 -18
  68. data/examples/graphics/line.rb +0 -33
  69. data/examples/graphics/png_types.rb +0 -23
  70. data/examples/graphics/polygons.rb +0 -17
  71. data/examples/graphics/remote_images.rb +0 -12
  72. data/examples/graphics/ruport_style_helpers.rb +0 -20
  73. data/examples/graphics/stroke_bounds.rb +0 -23
  74. data/examples/m17n/chinese_text_wrapping.rb +0 -20
  75. data/examples/m17n/euro.rb +0 -16
  76. data/examples/m17n/sjis.rb +0 -29
  77. data/examples/m17n/utf8.rb +0 -14
  78. data/examples/m17n/win_ansi_charset.rb +0 -55
  79. data/examples/text/alignment.rb +0 -19
  80. data/examples/text/dfont.rb +0 -49
  81. data/examples/text/family_based_styling.rb +0 -25
  82. data/examples/text/flowing_text_with_header_and_footer.rb +0 -37
  83. data/examples/text/font_calculations.rb +0 -92
  84. data/examples/text/font_size.rb +0 -34
  85. data/examples/text/kerning.rb +0 -31
  86. data/examples/text/simple_text.rb +0 -18
  87. data/examples/text/simple_text_ttf.rb +0 -18
  88. data/examples/text/span.rb +0 -30
  89. data/examples/text/text_box.rb +0 -26
  90. data/examples/text/text_flow.rb +0 -68
  91. data/lib/prawn/compatibility.rb +0 -38
  92. data/lib/prawn/document.rb +0 -309
  93. data/lib/prawn/document/annotations.rb +0 -63
  94. data/lib/prawn/document/bounding_box.rb +0 -368
  95. data/lib/prawn/document/destinations.rb +0 -81
  96. data/lib/prawn/document/internals.rb +0 -126
  97. data/lib/prawn/document/page_geometry.rb +0 -79
  98. data/lib/prawn/document/span.rb +0 -55
  99. data/lib/prawn/document/text.rb +0 -185
  100. data/lib/prawn/document/text/box.rb +0 -76
  101. data/lib/prawn/document/text/wrapping.rb +0 -59
  102. data/lib/prawn/encoding.rb +0 -121
  103. data/lib/prawn/errors.rb +0 -40
  104. data/lib/prawn/font.rb +0 -277
  105. data/lib/prawn/font/afm.rb +0 -202
  106. data/lib/prawn/font/dfont.rb +0 -31
  107. data/lib/prawn/font/ttf.rb +0 -326
  108. data/lib/prawn/graphics.rb +0 -257
  109. data/lib/prawn/graphics/color.rb +0 -140
  110. data/lib/prawn/images.rb +0 -339
  111. data/lib/prawn/images/jpg.rb +0 -45
  112. data/lib/prawn/images/png.rb +0 -199
  113. data/lib/prawn/literal_string.rb +0 -14
  114. data/lib/prawn/measurement_extensions.rb +0 -46
  115. data/lib/prawn/measurements.rb +0 -71
  116. data/lib/prawn/name_tree.rb +0 -165
  117. data/lib/prawn/pdf_object.rb +0 -73
  118. data/lib/prawn/reference.rb +0 -59
  119. data/spec/annotations_spec.rb +0 -90
  120. data/spec/bounding_box_spec.rb +0 -141
  121. data/spec/destinations_spec.rb +0 -15
  122. data/spec/document_spec.rb +0 -193
  123. data/spec/font_spec.rb +0 -234
  124. data/spec/graphics_spec.rb +0 -209
  125. data/spec/images_spec.rb +0 -68
  126. data/spec/jpg_spec.rb +0 -25
  127. data/spec/measurement_units_spec.rb +0 -23
  128. data/spec/name_tree_spec.rb +0 -103
  129. data/spec/pdf_object_spec.rb +0 -112
  130. data/spec/png_spec.rb +0 -196
  131. data/spec/reference_spec.rb +0 -42
  132. data/spec/spec_helper.rb +0 -23
  133. data/spec/text_spec.rb +0 -178
  134. data/vendor/pdf-inspector/README +0 -18
  135. data/vendor/pdf-inspector/lib/pdf/inspector.rb +0 -25
  136. data/vendor/pdf-inspector/lib/pdf/inspector/graphics.rb +0 -80
  137. data/vendor/pdf-inspector/lib/pdf/inspector/page.rb +0 -16
  138. data/vendor/pdf-inspector/lib/pdf/inspector/text.rb +0 -31
  139. data/vendor/pdf-inspector/lib/pdf/inspector/xobject.rb +0 -19
  140. data/vendor/ttfunk/data/fonts/DejaVuSans.ttf +0 -0
  141. data/vendor/ttfunk/data/fonts/comicsans.ttf +0 -0
  142. data/vendor/ttfunk/example.rb +0 -45
  143. data/vendor/ttfunk/lib/ttfunk.rb +0 -102
  144. data/vendor/ttfunk/lib/ttfunk/directory.rb +0 -17
  145. data/vendor/ttfunk/lib/ttfunk/encoding/mac_roman.rb +0 -88
  146. data/vendor/ttfunk/lib/ttfunk/encoding/windows_1252.rb +0 -69
  147. data/vendor/ttfunk/lib/ttfunk/reader.rb +0 -44
  148. data/vendor/ttfunk/lib/ttfunk/resource_file.rb +0 -78
  149. data/vendor/ttfunk/lib/ttfunk/subset.rb +0 -18
  150. data/vendor/ttfunk/lib/ttfunk/subset/base.rb +0 -141
  151. data/vendor/ttfunk/lib/ttfunk/subset/mac_roman.rb +0 -46
  152. data/vendor/ttfunk/lib/ttfunk/subset/unicode.rb +0 -48
  153. data/vendor/ttfunk/lib/ttfunk/subset/unicode_8bit.rb +0 -63
  154. data/vendor/ttfunk/lib/ttfunk/subset/windows_1252.rb +0 -51
  155. data/vendor/ttfunk/lib/ttfunk/subset_collection.rb +0 -72
  156. data/vendor/ttfunk/lib/ttfunk/table.rb +0 -46
  157. data/vendor/ttfunk/lib/ttfunk/table/cmap.rb +0 -34
  158. data/vendor/ttfunk/lib/ttfunk/table/cmap/format00.rb +0 -54
  159. data/vendor/ttfunk/lib/ttfunk/table/cmap/format04.rb +0 -126
  160. data/vendor/ttfunk/lib/ttfunk/table/cmap/subtable.rb +0 -79
  161. data/vendor/ttfunk/lib/ttfunk/table/glyf.rb +0 -64
  162. data/vendor/ttfunk/lib/ttfunk/table/glyf/compound.rb +0 -81
  163. data/vendor/ttfunk/lib/ttfunk/table/glyf/simple.rb +0 -37
  164. data/vendor/ttfunk/lib/ttfunk/table/head.rb +0 -44
  165. data/vendor/ttfunk/lib/ttfunk/table/hhea.rb +0 -41
  166. data/vendor/ttfunk/lib/ttfunk/table/hmtx.rb +0 -47
  167. data/vendor/ttfunk/lib/ttfunk/table/kern.rb +0 -79
  168. data/vendor/ttfunk/lib/ttfunk/table/kern/format0.rb +0 -62
  169. data/vendor/ttfunk/lib/ttfunk/table/loca.rb +0 -43
  170. data/vendor/ttfunk/lib/ttfunk/table/maxp.rb +0 -40
  171. data/vendor/ttfunk/lib/ttfunk/table/name.rb +0 -119
  172. data/vendor/ttfunk/lib/ttfunk/table/os2.rb +0 -78
  173. data/vendor/ttfunk/lib/ttfunk/table/post.rb +0 -91
  174. data/vendor/ttfunk/lib/ttfunk/table/post/format10.rb +0 -43
  175. data/vendor/ttfunk/lib/ttfunk/table/post/format20.rb +0 -35
  176. data/vendor/ttfunk/lib/ttfunk/table/post/format25.rb +0 -23
  177. data/vendor/ttfunk/lib/ttfunk/table/post/format30.rb +0 -17
  178. data/vendor/ttfunk/lib/ttfunk/table/post/format40.rb +0 -17
  179. data/vendor/ttfunk/lib/ttfunk/table/simple.rb +0 -14
@@ -1,31 +0,0 @@
1
- require 'prawn/font/ttf'
2
-
3
- module Prawn
4
- class Font
5
- class DFont < TTF
6
- # Returns a list of the names of all named fonts in the given dfont file.
7
- # Note that fonts are not required to be named in a dfont file, so the
8
- # list may be empty even if the file does contain fonts. Also, note that
9
- # the list is returned in no particular order, so the first font in the
10
- # list is not necessarily the font at index 0 in the file.
11
- def self.named_fonts(file)
12
- TTFunk::ResourceFile.open(file) do |file|
13
- return file.resources_for("sfnt")
14
- end
15
- end
16
-
17
- # Returns the number of fonts contained in the dfont file.
18
- def self.font_count(file)
19
- TTFunk::ResourceFile.open(file) do |file|
20
- return file.map["sfnt"][:list].length
21
- end
22
- end
23
-
24
- private
25
-
26
- def read_ttf_file
27
- TTFunk::File.from_dfont(@name, @options[:font] || 0)
28
- end
29
- end
30
- end
31
- end
@@ -1,326 +0,0 @@
1
- require 'ttfunk'
2
- require 'ttfunk/subset_collection'
3
-
4
- module Prawn
5
- class Font
6
- class TTF < Font
7
- attr_reader :ttf, :subsets
8
-
9
- def initialize(document, name, options={})
10
- super
11
-
12
- @ttf = read_ttf_file
13
- @subsets = TTFunk::SubsetCollection.new(@ttf)
14
-
15
- @attributes = {}
16
- @bounding_boxes = {}
17
- @char_widths = {}
18
- @has_kerning_data = @ttf.kerning.exists? && @ttf.kerning.tables.any?
19
-
20
- @ascender = Integer(@ttf.ascent * scale_factor)
21
- @descender = Integer(@ttf.descent * scale_factor)
22
- @line_gap = Integer(@ttf.line_gap * scale_factor)
23
- end
24
-
25
- # +string+ must be UTF8-encoded.
26
- def width_of(string, options={})
27
- scale = (options[:size] || size) / 1000.0
28
- if options[:kerning]
29
- kern(string).inject(0) do |s,r|
30
- if r.is_a?(Numeric)
31
- s - r
32
- else
33
- r.inject(s) { |s2, u| s2 + character_width_by_code(u) }
34
- end
35
- end * scale
36
- else
37
- string.unpack("U*").inject(0) do |s,r|
38
- s + character_width_by_code(r)
39
- end * scale
40
- end
41
- end
42
-
43
- def bbox
44
- @bbox ||= @ttf.bbox.map { |i| Integer(i * scale_factor) }
45
- end
46
-
47
- def has_kerning_data?
48
- @has_kerning_data
49
- end
50
-
51
- # Perform any changes to the string that need to happen
52
- # before it is rendered to the canvas. Returns an array of
53
- # subset "chunks", where the even-numbered indices are the
54
- # font subset number, and the following entry element is
55
- # either a string or an array (for kerned text).
56
- #
57
- # The +text+ parameter must be UTF8-encoded.
58
- def encode_text(text,options={})
59
- text = text.chomp
60
-
61
- if options[:kerning]
62
- last_subset = nil
63
- kern(text).inject([]) do |result, element|
64
- if element.is_a?(Numeric)
65
- result.last[1] = [result.last[1]] unless result.last[1].is_a?(Array)
66
- result.last[1] << element
67
- result
68
- else
69
- encoded = @subsets.encode(element)
70
-
71
- if encoded.first[0] == last_subset
72
- result.last[1] << encoded.first[1]
73
- encoded.shift
74
- end
75
-
76
- if encoded.any?
77
- last_subset = encoded.last[0]
78
- result + encoded
79
- else
80
- result
81
- end
82
- end
83
- end
84
- else
85
- @subsets.encode(text.unpack("U*"))
86
- end
87
- end
88
-
89
- def basename
90
- @basename ||= @ttf.name.postscript_name
91
- end
92
-
93
- # not sure how to compute this for true-type fonts...
94
- def stemV
95
- 0
96
- end
97
-
98
- def italic_angle
99
- @italic_angle ||= if @ttf.postscript.exists?
100
- raw = @ttf.postscript.italic_angle
101
- hi, low = raw >> 16, raw & 0xFF
102
- hi = -((hi ^ 0xFFFF) + 1) if hi & 0x8000 != 0
103
- "#{hi}.#{low}".to_f
104
- else
105
- 0
106
- end
107
- end
108
-
109
- def cap_height
110
- @cap_height ||= begin
111
- height = @ttf.os2.exists? && @ttf.os2.cap_height || 0
112
- height == 0 ? ascender : height
113
- end
114
- end
115
-
116
- def x_height
117
- # FIXME: seems like if os2 table doesn't exist, we could
118
- # just find the height of the lower-case 'x' glyph?
119
- @ttf.os2.exists? && @ttf.os2.x_height || 0
120
- end
121
-
122
- def family_class
123
- @family_class ||= (@ttf.os2.exists? && @ttf.os2.family_class || 0) >> 8
124
- end
125
-
126
- def serif?
127
- @serif ||= [1,2,3,4,5,7].include?(family_class)
128
- end
129
-
130
- def script?
131
- @script ||= family_class == 10
132
- end
133
-
134
- def pdf_flags
135
- @flags ||= begin
136
- flags = 0
137
- flags |= 0x0001 if @ttf.postscript.fixed_pitch?
138
- flags |= 0x0002 if serif?
139
- flags |= 0x0008 if script?
140
- flags |= 0x0040 if italic_angle != 0
141
- flags |= 0x0004 # assume the font contains at least some non-latin characters
142
- end
143
- end
144
-
145
- def normalize_encoding(text)
146
- if text.respond_to?(:encode!)
147
- # if we're running under a M17n aware VM, ensure the string provided is
148
- # UTF-8 (by converting it if necessary)
149
- begin
150
- text.encode!("UTF-8")
151
- rescue
152
- raise Prawn::Errors::IncompatibleStringEncoding, "Encoding " +
153
- "#{text.encoding} can not be transparently converted to UTF-8. " +
154
- "Please ensure the encoding of the string you are attempting " +
155
- "to use is set correctly"
156
- end
157
- else
158
- # on a non M17N aware VM, use unpack as a hackish way to verify the
159
- # string is valid utf-8. I thought it was better than loading iconv
160
- # though.
161
- begin
162
- text.unpack("U*")
163
- rescue
164
- raise Prawn::Errors::IncompatibleStringEncoding, "The string you " +
165
- "are attempting to render is not encoded in valid UTF-8."
166
- end
167
- end
168
- end
169
-
170
- private
171
-
172
- def cmap
173
- @cmap ||= @ttf.cmap.unicode.first or raise("no unicode cmap for font")
174
- end
175
-
176
- # +string+ must be UTF8-encoded.
177
- #
178
- # Returns an array. If an element is a numeric, it represents the
179
- # kern amount to inject at that position. Otherwise, the element
180
- # is an array of UTF-16 characters.
181
- def kern(string)
182
- a = []
183
-
184
- string.unpack("U*").each do |r|
185
- if a.empty?
186
- a << [r]
187
- elsif (kern = kern_pairs_table[[cmap[a.last.last], cmap[r]]])
188
- kern *= scale_factor
189
- a << -kern << [r]
190
- else
191
- a.last << r
192
- end
193
- end
194
-
195
- a
196
- end
197
-
198
- def kern_pairs_table
199
- @kerning_data ||= has_kerning_data? ? @ttf.kerning.tables.first.pairs : {}
200
- end
201
-
202
- def cid_to_gid_map
203
- max = cmap.code_map.keys.max
204
- (0..max).map { |cid| cmap[cid] }.pack("n*")
205
- end
206
-
207
- def hmtx
208
- @hmtx ||= @ttf.horizontal_metrics
209
- end
210
-
211
- def character_width_by_code(code)
212
- return 0 unless cmap[code]
213
- @char_widths[code] ||= Integer(hmtx.widths[cmap[code]] * scale_factor)
214
- end
215
-
216
- def scale_factor
217
- @scale ||= 1000.0 / @ttf.header.units_per_em
218
- end
219
-
220
- def register(subset)
221
- temp_name = @ttf.name.postscript_name
222
- @document.ref(:Type => :Font, :BaseFont => temp_name) { |ref| embed(ref, subset) }
223
- end
224
-
225
- def embed(reference, subset)
226
- font_content = @subsets[subset].encode
227
-
228
- # FIXME: we need postscript_name and glyph widths from the font
229
- # subset. Perhaps this could be done by querying the subset,
230
- # rather than by parsing the font that the subset produces?
231
- font = TTFunk::File.new(font_content)
232
-
233
- # empirically, it looks like Adobe Reader will not display fonts
234
- # if their font name is more than 33 bytes long. Strange. But true.
235
- basename = font.name.postscript_name[0, 33]
236
-
237
- raise "Can't detect a postscript name for #{file}" if basename.nil?
238
-
239
- compressed_font = Zlib::Deflate.deflate(font_content)
240
-
241
- fontfile = @document.ref(:Length => compressed_font.size,
242
- :Length1 => font_content.size,
243
- :Filter => :FlateDecode )
244
- fontfile << compressed_font
245
-
246
- descriptor = @document.ref(:Type => :FontDescriptor,
247
- :FontName => basename,
248
- :FontFile2 => fontfile,
249
- :FontBBox => bbox,
250
- :Flags => pdf_flags,
251
- :StemV => stemV,
252
- :ItalicAngle => italic_angle,
253
- :Ascent => ascender,
254
- :Descent => descender,
255
- :CapHeight => cap_height,
256
- :XHeight => x_height)
257
-
258
- hmtx = font.horizontal_metrics
259
- widths = font.cmap.tables.first.code_map.map { |gid|
260
- Integer(hmtx.widths[gid] * scale_factor) }[32..-1]
261
-
262
- # It would be nice to have Encoding set for the macroman subsets,
263
- # and only do a ToUnicode cmap for non-encoded unicode subsets.
264
- # However, apparently Adobe Reader won't render MacRoman encoded
265
- # subsets if original font contains unicode characters. (It has to
266
- # be some flag or something that ttfunk is simply copying over...
267
- # but I can't figure out which flag that is.)
268
- #
269
- # For now, it's simplest to just create a unicode cmap for every font.
270
- # It offends my inner purist, but it'll do.
271
-
272
- map = @subsets[subset].to_unicode_map
273
-
274
- ranges = [[]]
275
- lines = map.keys.sort.inject("") do |s, code|
276
- ranges << [] if ranges.last.length >= 100
277
- unicode = map[code]
278
- ranges.last << "<%02x><%04x>" % [code, unicode]
279
- end
280
-
281
- range_blocks = ranges.inject("") do |s, list|
282
- s << "%d beginbfchar\n%s\nendbfchar\n" % [list.length, list.join("\n")]
283
- end
284
-
285
- to_unicode_cmap = UNICODE_CMAP_TEMPLATE % range_blocks.strip
286
-
287
- cmap = @document.ref({})
288
- cmap << to_unicode_cmap
289
- cmap.compress_stream
290
-
291
- reference.data.update(:Subtype => :TrueType,
292
- :BaseFont => basename,
293
- :FontDescriptor => descriptor,
294
- :FirstChar => 32,
295
- :LastChar => 255,
296
- :Widths => @document.ref(widths),
297
- :ToUnicode => cmap)
298
- end
299
-
300
- UNICODE_CMAP_TEMPLATE = <<-STR.strip.gsub(/^\s*/, "")
301
- /CIDInit /ProcSet findresource begin
302
- 12 dict begin
303
- begincmap
304
- /CIDSystemInfo <<
305
- /Registry (Adobe)
306
- /Ordering (UCS)
307
- /Supplement 0
308
- >> def
309
- /CMapName /Adobe-Identity-UCS def
310
- /CMapType 2 def
311
- 1 begincodespacerange
312
- <00><ff>
313
- endcodespacerange
314
- %s
315
- endcmap
316
- CMapName currentdict /CMap defineresource pop
317
- end
318
- end
319
- STR
320
-
321
- def read_ttf_file
322
- TTFunk::File.open(@name)
323
- end
324
- end
325
- end
326
- end
@@ -1,257 +0,0 @@
1
- # encoding: utf-8
2
-
3
- # graphics.rb : Implements PDF drawing primitives
4
- #
5
- # Copyright April 2008, Gregory Brown. All Rights Reserved.
6
- #
7
- # This is free software. Please see the LICENSE and COPYING files for details.
8
-
9
- require "enumerator"
10
- require "prawn/graphics/color"
11
-
12
- module Prawn
13
-
14
- # Implements the drawing facilities for Prawn::Document.
15
- # Use this to draw the most beautiful imaginable things.
16
- #
17
- # This file lifts and modifies several of PDF::Writer's graphics functions
18
- # ruby-pdf.rubyforge.org
19
- #
20
- module Graphics
21
-
22
- include Color
23
-
24
- #######################################################################
25
- # Low level drawing operations must translate to absolute coords! #
26
- #######################################################################
27
-
28
- # Moves the drawing position to a given point. The point can be
29
- # specified as a tuple or a flattened argument list
30
- #
31
- # pdf.move_to [100,50]
32
- # pdf.move_to(100,50)
33
- #
34
- def move_to(*point)
35
- x,y = translate(point)
36
- add_content("%.3f %.3f m" % [ x, y ])
37
- end
38
-
39
- # Draws a line from the current drawing position to the specified point.
40
- # The destination may be described as a tuple or a flattened list:
41
- #
42
- # pdf.line_to [50,50]
43
- # pdf.line_to(50,50)
44
- #
45
- def line_to(*point)
46
- x,y = translate(point)
47
- add_content("%.3f %.3f l" % [ x, y ])
48
- end
49
-
50
- # Draws a Bezier curve from the current drawing position to the
51
- # specified point, bounded by two additional points.
52
- #
53
- # pdf.curve_to [100,100], :bounds => [[90,90],[75,75]]
54
- #
55
- def curve_to(dest,options={})
56
- options[:bounds] or raise Prawn::Errors::InvalidGraphicsPath,
57
- "Bounding points for bezier curve must be specified "+
58
- "as :bounds => [[x1,y1],[x2,y2]]"
59
-
60
- curve_points = (options[:bounds] << dest).map { |e| translate(e) }
61
- add_content("%.3f %.3f %.3f %.3f %.3f %.3f c" %
62
- curve_points.flatten )
63
- end
64
-
65
- # Draws a rectangle given <tt>point</tt>, <tt>width</tt> and
66
- # <tt>height</tt>. The rectangle is bounded by its upper-left corner.
67
- #
68
- # pdf.rectangle [300,300], 100, 200
69
- #
70
- def rectangle(point,width,height)
71
- x,y = translate(point)
72
- add_content("%.3f %.3f %.3f %.3f re" % [ x, y - height, width, height ])
73
- end
74
-
75
- ###########################################################
76
- # Higher level functions: May use relative coords #
77
- ###########################################################
78
-
79
- # Sets line thickness to the <tt>width</tt> specified.
80
- #
81
- def line_width=(width)
82
- @line_width = width
83
- add_content("#{width} w")
84
- end
85
-
86
- # When called without an argument, returns the current line thickness.
87
- # When called with an argument, sets the line thickness to the specified
88
- # value (in PDF points)
89
- #
90
- # pdf.line_width #=> 1
91
- # pdf.line_width(5)
92
- # pdf.line_width #=> 5
93
- #
94
- def line_width(width=nil)
95
- if width
96
- self.line_width = width
97
- else
98
- @line_width || 1
99
- end
100
- end
101
-
102
- # Draws a line from one point to another. Points may be specified as
103
- # tuples or flattened argument list:
104
- #
105
- # pdf.line [100,100], [200,250]
106
- # pdf.line(100,100,200,250)
107
- #
108
- def line(*points)
109
- x0,y0,x1,y1 = points.flatten
110
- move_to(x0, y0)
111
- line_to(x1, y1)
112
- end
113
-
114
- # Draws a horizontal line from <tt>x1</tt> to <tt>x2</tt> at the
115
- # current <tt>y</tt> position, or the position specified by the :at option.
116
- #
117
- # # draw a line from [25, 75] to [100, 75]
118
- # horizontal_line 25, 100, :at => 75
119
- #
120
- def horizontal_line(x1,x2,options={})
121
- if options[:at]
122
- y1 = options[:at]
123
- else
124
- y1 = y - bounds.absolute_bottom
125
- end
126
-
127
- line(x1,y1,x2,y1)
128
- end
129
-
130
- # Draws a horizontal line from the left border to the right border of the
131
- # bounding box at the current <tt>y</tt> position.
132
- #
133
- def horizontal_rule
134
- horizontal_line(bounds.left, bounds.right)
135
- end
136
-
137
- # Draws a vertical line at the x cooordinate given by :at from y1 to y2.
138
- #
139
- # # draw a line from [25, 100] to [25, 300]
140
- # vertical_line 100, 300, :at => 25
141
- #
142
- def vertical_line(y1,y2,params)
143
- line(params[:at],y1,params[:at],y2)
144
- end
145
-
146
- # Draws a Bezier curve between two points, bounded by two additional
147
- # points
148
- #
149
- # pdf.curve [50,100], [100,100], :bounds => [[90,90],[75,75]]
150
- #
151
- def curve(origin,dest, options={})
152
- move_to(*origin)
153
- curve_to(dest,options)
154
- end
155
-
156
- # This constant is used to approximate a symmetrical arc using a cubic
157
- # Bezier curve.
158
- #
159
- KAPPA = 4.0 * ((Math.sqrt(2) - 1.0) / 3.0)
160
-
161
- # Draws a circle of radius <tt>:radius</tt> with the centre-point at <tt>point</tt>
162
- # as a complete subpath. The drawing point will be moved to the
163
- # centre-point upon completion of the drawing the circle.
164
- #
165
- # pdf.circle_at [100,100], :radius => 25
166
- #
167
- def circle_at(point, options)
168
- x,y = point
169
- ellipse_at [x, y], options[:radius]
170
- end
171
-
172
- # Draws an ellipse of +x+ radius <tt>r1</tt> and +y+ radius <tt>r2</tt>
173
- # with the centre-point at <tt>point</tt> as a complete subpath. The
174
- # drawing point will be moved to the centre-point upon completion of the
175
- # drawing the ellipse.
176
- #
177
- # # draws an ellipse with x-radius 25 and y-radius 50
178
- # pdf.ellipse_at [100,100], 25, 50
179
- #
180
- def ellipse_at(point, r1, r2 = r1)
181
- x, y = point
182
- l1 = r1 * KAPPA
183
- l2 = r2 * KAPPA
184
-
185
- move_to(x + r1, y)
186
-
187
- # Upper right hand corner
188
- curve_to [x, y + r2],
189
- :bounds => [[x + r1, y + l1], [x + l2, y + r2]]
190
-
191
- # Upper left hand corner
192
- curve_to [x - r1, y],
193
- :bounds => [[x - l2, y + r2], [x - r1, y + l1]]
194
-
195
- # Lower left hand corner
196
- curve_to [x, y - r2],
197
- :bounds => [[x - r1, y - l1], [x - l2, y - r2]]
198
-
199
- # Lower right hand corner
200
- curve_to [x + r1, y],
201
- :bounds => [[x + l2, y - r2], [x + r1, y - l1]]
202
-
203
- move_to(x, y)
204
- end
205
-
206
- # Draws a polygon from the specified points.
207
- #
208
- # # draws a snazzy triangle
209
- # pdf.polygon [100,100], [100,200], [200,200]
210
- #
211
- def polygon(*points)
212
- move_to points[0]
213
- (points << points[0]).each_cons(2) do |p1,p2|
214
- line_to(*p2)
215
- end
216
- end
217
-
218
- # Strokes and closes the current path. See Graphic::Color for color details
219
- #
220
- def stroke
221
- yield if block_given?
222
- add_content "S"
223
- end
224
-
225
- # Draws and strokes a rectangle represented by the current bounding box
226
- #
227
- def stroke_bounds
228
- stroke_rectangle bounds.top_left, bounds.width, bounds.height
229
- end
230
-
231
- # Fills and closes the current path. See Graphic::Color for color details
232
- #
233
- def fill
234
- yield if block_given?
235
- add_content "f"
236
- end
237
-
238
- # Fills, strokes, and closes the current path. See Graphic::Color for color details
239
- #
240
- def fill_and_stroke
241
- yield if block_given?
242
- add_content "b"
243
- end
244
-
245
- private
246
-
247
- def translate(*point)
248
- x,y = point.flatten
249
- [@bounding_box.absolute_left + x, @bounding_box.absolute_bottom + y]
250
- end
251
-
252
- def translate!(point)
253
- point.replace(translate(point))
254
- end
255
-
256
- end
257
- end