fullcirclegroup-prawn 0.2.99.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (117) hide show
  1. data/COPYING +340 -0
  2. data/LICENSE +56 -0
  3. data/README +47 -0
  4. data/Rakefile +76 -0
  5. data/data/fonts/Activa.ttf +0 -0
  6. data/data/fonts/Chalkboard.ttf +0 -0
  7. data/data/fonts/Courier-Bold.afm +342 -0
  8. data/data/fonts/Courier-BoldOblique.afm +342 -0
  9. data/data/fonts/Courier-Oblique.afm +342 -0
  10. data/data/fonts/Courier.afm +342 -0
  11. data/data/fonts/DejaVuSans.ttf +0 -0
  12. data/data/fonts/Dustismo_Roman.ttf +0 -0
  13. data/data/fonts/Helvetica-Bold.afm +2827 -0
  14. data/data/fonts/Helvetica-BoldOblique.afm +2827 -0
  15. data/data/fonts/Helvetica-Oblique.afm +3051 -0
  16. data/data/fonts/Helvetica.afm +3051 -0
  17. data/data/fonts/MustRead.html +19 -0
  18. data/data/fonts/Symbol.afm +213 -0
  19. data/data/fonts/Times-Bold.afm +2588 -0
  20. data/data/fonts/Times-BoldItalic.afm +2384 -0
  21. data/data/fonts/Times-Italic.afm +2667 -0
  22. data/data/fonts/Times-Roman.afm +2419 -0
  23. data/data/fonts/ZapfDingbats.afm +225 -0
  24. data/data/fonts/comicsans.ttf +0 -0
  25. data/data/fonts/gkai00mp.ttf +0 -0
  26. data/data/images/arrow.png +0 -0
  27. data/data/images/arrow2.png +0 -0
  28. data/data/images/barcode_issue.png +0 -0
  29. data/data/images/dice.alpha +0 -0
  30. data/data/images/dice.dat +0 -0
  31. data/data/images/dice.png +0 -0
  32. data/data/images/page_white_text.alpha +0 -0
  33. data/data/images/page_white_text.dat +0 -0
  34. data/data/images/page_white_text.png +0 -0
  35. data/data/images/pigs.jpg +0 -0
  36. data/data/images/rails.dat +0 -0
  37. data/data/images/rails.png +0 -0
  38. data/data/images/ruport.png +0 -0
  39. data/data/images/ruport_data.dat +0 -0
  40. data/data/images/ruport_transparent.png +0 -0
  41. data/data/images/ruport_type0.png +0 -0
  42. data/data/images/stef.jpg +0 -0
  43. data/data/images/web-links.dat +1 -0
  44. data/data/images/web-links.png +0 -0
  45. data/data/shift_jis_text.txt +1 -0
  46. data/examples/addressbook.csv +6 -0
  47. data/examples/alignment.rb +16 -0
  48. data/examples/bounding_boxes.rb +30 -0
  49. data/examples/canvas.rb +12 -0
  50. data/examples/cell.rb +38 -0
  51. data/examples/chinese_text_wrapping.rb +17 -0
  52. data/examples/currency.csv +1834 -0
  53. data/examples/curves.rb +10 -0
  54. data/examples/family_based_styling.rb +21 -0
  55. data/examples/fancy_table.rb +61 -0
  56. data/examples/flowing_text_with_header_and_footer.rb +72 -0
  57. data/examples/font_size.rb +27 -0
  58. data/examples/hexagon.rb +14 -0
  59. data/examples/image.rb +23 -0
  60. data/examples/image2.rb +13 -0
  61. data/examples/image_flow.rb +34 -0
  62. data/examples/kerning.rb +27 -0
  63. data/examples/lazy_bounding_boxes.rb +19 -0
  64. data/examples/line.rb +31 -0
  65. data/examples/multi_page_layout.rb +14 -0
  66. data/examples/page_geometry.rb +28 -0
  67. data/examples/png_types.rb +23 -0
  68. data/examples/polygons.rb +16 -0
  69. data/examples/position_by_baseline.rb +26 -0
  70. data/examples/ruport_formatter.rb +50 -0
  71. data/examples/ruport_helpers.rb +18 -0
  72. data/examples/russian_boxes.rb +34 -0
  73. data/examples/simple_text.rb +15 -0
  74. data/examples/simple_text_ttf.rb +16 -0
  75. data/examples/sjis.rb +21 -0
  76. data/examples/span.rb +27 -0
  77. data/examples/table.rb +47 -0
  78. data/examples/table_header_color.rb +16 -0
  79. data/examples/text_flow.rb +65 -0
  80. data/examples/top_and_bottom_cells.rb +40 -0
  81. data/examples/utf8.rb +12 -0
  82. data/lib/prawn.rb +67 -0
  83. data/lib/prawn/compatibility.rb +46 -0
  84. data/lib/prawn/document.rb +309 -0
  85. data/lib/prawn/document/bounding_box.rb +362 -0
  86. data/lib/prawn/document/internals.rb +113 -0
  87. data/lib/prawn/document/page_geometry.rb +79 -0
  88. data/lib/prawn/document/span.rb +47 -0
  89. data/lib/prawn/document/table.rb +350 -0
  90. data/lib/prawn/document/text.rb +196 -0
  91. data/lib/prawn/errors.rb +48 -0
  92. data/lib/prawn/font.rb +356 -0
  93. data/lib/prawn/font/cmap.rb +59 -0
  94. data/lib/prawn/font/metrics.rb +378 -0
  95. data/lib/prawn/font/wrapping.rb +47 -0
  96. data/lib/prawn/graphics.rb +252 -0
  97. data/lib/prawn/graphics/cell.rb +264 -0
  98. data/lib/prawn/graphics/color.rb +132 -0
  99. data/lib/prawn/images.rb +336 -0
  100. data/lib/prawn/images/jpg.rb +45 -0
  101. data/lib/prawn/images/png.rb +199 -0
  102. data/lib/prawn/pdf_object.rb +73 -0
  103. data/lib/prawn/reference.rb +56 -0
  104. data/spec/bounding_box_spec.rb +141 -0
  105. data/spec/document_spec.rb +181 -0
  106. data/spec/font_spec.rb +141 -0
  107. data/spec/graphics_spec.rb +209 -0
  108. data/spec/images_spec.rb +68 -0
  109. data/spec/jpg_spec.rb +25 -0
  110. data/spec/metrics_spec.rb +62 -0
  111. data/spec/pdf_object_spec.rb +112 -0
  112. data/spec/png_spec.rb +196 -0
  113. data/spec/reference_spec.rb +42 -0
  114. data/spec/spec_helper.rb +23 -0
  115. data/spec/table_spec.rb +179 -0
  116. data/spec/text_spec.rb +135 -0
  117. metadata +181 -0
@@ -0,0 +1,59 @@
1
+ # encoding: utf-8
2
+
3
+ # cmap.rb : class for building ToUnicode CMaps for Type0 fonts
4
+ #
5
+ # Copyright May 2008, Gregory Brown / James Healy. All Rights Reserved.
6
+ #
7
+ # This is free software. Please see the LICENSE and COPYING files for details.
8
+
9
+ module Prawn
10
+ class Font
11
+ class CMap #:nodoc:
12
+
13
+ def initialize
14
+ @codes = {}
15
+ end
16
+
17
+ def [](c)
18
+ @codes[c]
19
+ end
20
+
21
+ def []=(c, v)
22
+ @codes[c] = v
23
+ end
24
+
25
+ def to_s
26
+ # TODO: learn what all this means. I just copied the basic structure
27
+ # from an existing PDF
28
+ # TODO: make this more efficient. The mapping can be specified in
29
+ # ranges instead of one -> one
30
+ res = "12 dict begin\n"
31
+ res << "begincmap\n"
32
+ res << "/CIDSystemInfo\n"
33
+ res << "<< /Registry (Adobe)\n"
34
+ res << "/Ordering (UCS)\n"
35
+ res << "/Supplement 0\n"
36
+ res << ">> def\n"
37
+ res << "/CMapName /Adobe-Identity-UCS def\n"
38
+ res << "/CMapType 2 def\n"
39
+ res << "begincodespacerange\n"
40
+ res << "<0000> <ffff>\n"
41
+ res << "endcodespacerange\n"
42
+ res << "9 beginbfchar\n"
43
+ @codes.keys.sort.each do |key|
44
+ val = @codes[key]
45
+ ccode = val.to_s(16)
46
+ ccode = ("0" * (4 - ccode.size)) + ccode
47
+ unicode = key.to_s(16)
48
+ unicode = ("0" * (4 - unicode.size)) + unicode
49
+ res << "<#{ccode}> <#{unicode}>\n"
50
+ end
51
+ res << "endbfchar\n"
52
+ res << "endcmap\n"
53
+ res << "CMapName currentdict /CMap defineresource pop\n"
54
+ res << "end\n"
55
+ res << "end\n"
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,378 @@
1
+ # encoding: utf-8
2
+
3
+ # metrics.rb : Font metrics parsers for AFM and TTF.
4
+ #
5
+ # Font::Metrics::Adobe is mainly a port of CPAN's Font::AFM
6
+ # http://search.cpan.org/~gaas/Font-AFM-1.19/AFM.pm
7
+ #
8
+ # Copyright May 2008, Gregory Brown / James Edward Gray II. All Rights Reserved.
9
+ #
10
+ # This is free software. Please see the LICENSE and COPYING files for details.
11
+
12
+ require 'prawn/encoding'
13
+
14
+ module Prawn
15
+ class Font
16
+ class Metrics #:nodoc:
17
+
18
+ include Prawn::Font::Wrapping
19
+
20
+ def self.[](font)
21
+ data[font] ||= (font.match(/\.ttf$/i) ? TTF : Adobe).new(font)
22
+ end
23
+
24
+ def self.data
25
+ @data ||= {}
26
+ end
27
+
28
+ def string_height(string,options={})
29
+ string = naive_wrap(string, options[:line_width], options[:font_size])
30
+ string.lines.to_a.length * font_height(options[:font_size])
31
+ end
32
+
33
+ def font_height(size)
34
+ (ascender - descender + line_gap) * size / 1000.0
35
+ end
36
+
37
+ class Adobe < Metrics #:nodoc:
38
+ attr_reader :attributes
39
+
40
+ def initialize(font_name)
41
+ @attributes = {}
42
+ @glyph_widths = {}
43
+ @bounding_boxes = {}
44
+ @kern_pairs = {}
45
+
46
+ file = font_name.sub(/\.afm$/,'') + '.afm'
47
+ unless file[0..0] == "/"
48
+ file = find_font(file)
49
+ end
50
+
51
+ parse_afm(file)
52
+ end
53
+
54
+ def bbox
55
+ fontbbox.split(/\s+/).map { |e| Integer(e) }
56
+ end
57
+
58
+ # calculates the width of the supplied string.
59
+ #
60
+ # String *must* be encoded as WinAnsi
61
+ #
62
+ def string_width(string, font_size, options = {})
63
+ scale = font_size / 1000.0
64
+
65
+ if options[:kerning]
66
+ kern(string).inject(0) do |s,r|
67
+ if r.is_a? String
68
+ s + string_width(r, font_size, :kerning => false)
69
+ else
70
+ s - (r * scale)
71
+ end
72
+ end
73
+ else
74
+ string.unpack("C*").inject(0) do |s,r|
75
+ s + latin_glyphs_table[r]
76
+ end * scale
77
+ end
78
+ end
79
+
80
+ # converts a string into an array with spacing offsets
81
+ # bewteen characters that need to be kerned
82
+ #
83
+ # String *must* be encoded as WinAnsi
84
+ #
85
+ def kern(string)
86
+ kerned = string.unpack("C*").inject([]) do |a,r|
87
+ if a.last.is_a? Array
88
+ if k = latin_kern_pairs_table[[a.last.last, r]]
89
+ a << k << [r]
90
+ else
91
+ a.last << r
92
+ end
93
+ else
94
+ a << [r]
95
+ end
96
+ a
97
+ end
98
+
99
+ kerned.map { |r|
100
+ i = r.is_a?(Array) ? r.pack("C*") : r
101
+ i.force_encoding("ISO-8859-1") if i.respond_to?(:force_encoding)
102
+ i.is_a?(Numeric) ? -i : i
103
+ }
104
+ end
105
+
106
+ def latin_kern_pairs_table
107
+ @kern_pairs_table ||= @kern_pairs.inject({}) do |h,p|
108
+ h[p[0].map { |n| Encoding::WinAnsi::CHARACTERS.index(n) }] = p[1]
109
+ h
110
+ end
111
+ end
112
+
113
+ def latin_glyphs_table
114
+ @glyphs_table ||= (0..255).map do |i|
115
+ @glyph_widths[Encoding::WinAnsi::CHARACTERS[i]].to_i
116
+ end
117
+ end
118
+
119
+ def ascender
120
+ @attributes["ascender"].to_i
121
+ end
122
+
123
+ def descender
124
+ @attributes["descender"].to_i
125
+ end
126
+
127
+ def line_gap
128
+ Float(bbox[3] - bbox[1]) - (ascender - descender)
129
+ end
130
+
131
+ # Hackish, but does the trick for now.
132
+ def method_missing(method, *args, &block)
133
+ name = method.to_s.delete("_")
134
+ @attributes.include?(name) ? @attributes[name] : super
135
+ end
136
+
137
+ def metrics_path
138
+ if m = ENV['METRICS']
139
+ @metrics_path ||= m.split(':')
140
+ else
141
+ @metrics_path ||= [
142
+ ".", "/usr/lib/afm",
143
+ "/usr/local/lib/afm",
144
+ "/usr/openwin/lib/fonts/afm/",
145
+ Prawn::BASEDIR+'/data/fonts/']
146
+ end
147
+ end
148
+
149
+ def has_kerning_data?
150
+ true
151
+ end
152
+
153
+ def type0?
154
+ false
155
+ end
156
+
157
+ # perform any changes to the string that need to happen
158
+ # before it is rendered to the canvas
159
+ #
160
+ # String *must* be encoded as WinAnsi
161
+ #
162
+ def convert_text(text, options={})
163
+ options[:kerning] ? kern(text) : text
164
+ end
165
+
166
+ private
167
+
168
+ def find_font(file)
169
+ metrics_path.find { |f| File.exist? "#{f}/#{file}" } + "/#{file}"
170
+ rescue NoMethodError
171
+ raise Prawn::Errors::UnknownFont,
172
+ "Couldn't find the font: #{file} in any of:\n" +
173
+ @metrics_path.join("\n")
174
+ end
175
+
176
+ def parse_afm(file_name)
177
+ section = []
178
+
179
+ File.foreach(file_name) do |line|
180
+ case line
181
+ when /^Start(\w+)/
182
+ section.push $1
183
+ next
184
+ when /^End(\w+)/
185
+ section.pop
186
+ next
187
+ end
188
+
189
+ case section
190
+ when ["FontMetrics", "CharMetrics"]
191
+ next unless line =~ /^CH?\s/
192
+
193
+ name = line[/\bN\s+(\.?\w+)\s*;/, 1]
194
+ @glyph_widths[name] = line[/\bWX\s+(\d+)\s*;/, 1].to_i
195
+ @bounding_boxes[name] = line[/\bB\s+([^;]+);/, 1].to_s.rstrip
196
+ when ["FontMetrics", "KernData", "KernPairs"]
197
+ next unless line =~ /^KPX\s+(\.?\w+)\s+(\.?\w+)\s+(-?\d+)/
198
+ @kern_pairs[[$1, $2]] = $3.to_i
199
+ when ["FontMetrics", "KernData", "TrackKern"],
200
+ ["FontMetrics", "Composites"]
201
+ next
202
+ else
203
+ parse_generic_afm_attribute(line)
204
+ end
205
+ end
206
+ end
207
+
208
+ def parse_generic_afm_attribute(line)
209
+ line =~ /(^\w+)\s+(.*)/
210
+ key, value = $1.to_s.downcase, $2
211
+
212
+ @attributes[key] = @attributes[key] ?
213
+ Array(@attributes[key]) << value : value
214
+ end
215
+ end
216
+
217
+ class TTF < Metrics #:nodoc:
218
+
219
+ attr_accessor :ttf
220
+
221
+ def initialize(font)
222
+ @ttf = TTFunk::File.new(font)
223
+ @attributes = {}
224
+ @glyph_widths = {}
225
+ @bounding_boxes = {}
226
+ @char_widths = {}
227
+ @has_kerning_data = !! @ttf.kern? && @ttf.kern.sub_tables[0]
228
+ end
229
+
230
+ def cmap
231
+ @cmap ||= @ttf.cmap.formats[4]
232
+ end
233
+
234
+ def string_width(string, font_size, options = {})
235
+ scale = font_size / 1000.0
236
+ if options[:kerning]
237
+ kern(string,:skip_conversion => true).inject(0) do |s,r|
238
+ if r.is_a? String
239
+ s + string_width(r, font_size, :kerning => false)
240
+ else
241
+ s + r * scale
242
+ end
243
+ end
244
+ else
245
+ string.unpack("U*").inject(0) do |s,r|
246
+ s + character_width_by_code(r)
247
+ end * scale
248
+ end
249
+ end
250
+
251
+ # TODO: NASTY.
252
+ def kern(string,options={})
253
+ a = []
254
+
255
+ string.unpack("U*").each do |r|
256
+ if a.last.is_a? Array
257
+ if kern = kern_pairs_table[[cmap[a.last.last], cmap[r]]]
258
+ kern *= scale_factor
259
+ a << kern << [r]
260
+ else
261
+ a.last << r
262
+ end
263
+ else
264
+ a << [r]
265
+ end
266
+ a
267
+ end
268
+
269
+ a.map { |r|
270
+ if options[:skip_conversion]
271
+ r.is_a?(Array) ? r.pack("U*") : r
272
+ else
273
+ i = r.is_a?(Array) ? r.pack("U*") : r
274
+ x = if i.is_a?(String)
275
+ unicode_codepoints = i.unpack("U*")
276
+ glyph_codes = unicode_codepoints.map { |u| cmap[u] }
277
+ glyph_codes.pack("n*")
278
+ else
279
+ i
280
+ end
281
+ x.is_a?(Numeric) ? -x : x
282
+ end
283
+ }
284
+ end
285
+
286
+ def glyph_widths
287
+ glyphs = cmap.values.uniq.sort
288
+ first_glyph = glyphs.shift
289
+ widths = [first_glyph, [Integer(hmtx[first_glyph][0] * scale_factor)]]
290
+ prev_glyph = first_glyph
291
+ glyphs.each do |glyph|
292
+ unless glyph == prev_glyph + 1
293
+ widths << glyph
294
+ widths << []
295
+ end
296
+ widths.last << Integer(hmtx[glyph][0] * scale_factor )
297
+ prev_glyph = glyph
298
+ end
299
+ widths
300
+ end
301
+
302
+ def bbox
303
+ [:x_min, :y_min, :x_max, :y_max].map do |atr|
304
+ Integer(@ttf.head.send(atr)) * scale_factor
305
+ end
306
+ end
307
+
308
+ def ascender
309
+ Integer(@ttf.hhea.ascent * scale_factor)
310
+ end
311
+
312
+ def descender
313
+ Integer(@ttf.hhea.descent * scale_factor)
314
+ end
315
+
316
+ def line_gap
317
+ Integer(@ttf.hhea.line_gap * scale_factor)
318
+ end
319
+
320
+ def basename
321
+ @basename ||= @ttf.name.postscript_name
322
+ end
323
+
324
+ # TODO: instead of creating a map that contains every glyph in the font,
325
+ # only include the glyphs that were used
326
+ def to_unicode_cmap
327
+ return @to_unicode if @to_unicode
328
+ @to_unicode = Prawn::Font::CMap.new
329
+ unicode_for_glyph = cmap.invert
330
+ glyphs = unicode_for_glyph.keys.uniq.sort
331
+ glyphs.each do |glyph|
332
+ @to_unicode[unicode_for_glyph[glyph]] = glyph
333
+ end
334
+ @to_unicode
335
+ end
336
+
337
+ def kern_pairs_table
338
+ @kerning_data ||= has_kerning_data? ? @ttf.kern.sub_tables[0] : {}
339
+ end
340
+
341
+ def has_kerning_data?
342
+ @has_kerning_data
343
+ end
344
+
345
+ def type0?
346
+ true
347
+ end
348
+
349
+ def convert_text(text,options)
350
+ text = text.chomp
351
+ if options[:kerning]
352
+ kern(text)
353
+ else
354
+ unicode_codepoints = text.unpack("U*")
355
+ glyph_codes = unicode_codepoints.map { |u| cmap[u] }
356
+ text = glyph_codes.pack("n*")
357
+ end
358
+ end
359
+
360
+ private
361
+
362
+ def hmtx
363
+ @hmtx ||= @ttf.hmtx.values
364
+ end
365
+
366
+ def character_width_by_code(code)
367
+ return 0 unless cmap[code]
368
+ @char_widths[code] ||= Integer(hmtx[cmap[code]][0] * scale_factor)
369
+ end
370
+
371
+ def scale_factor
372
+ @scale ||= 1000 * Float(@ttf.head.units_per_em)**-1
373
+ end
374
+
375
+ end
376
+ end
377
+ end
378
+ end
@@ -0,0 +1,47 @@
1
+ # encoding: utf-8
2
+
3
+ # wrapping.rb : Implementation of naive text wrap
4
+ #
5
+ # Copyright May 2008, Michael Daines. All Rights Reserved.
6
+ #
7
+ # This is free software. Please see the LICENSE and COPYING files for details.
8
+ module Prawn
9
+ class Font
10
+ module Wrapping #:nodoc:
11
+ ruby_18 { $KCODE="U" }
12
+
13
+ # TODO: Replace with TeX optimal algorithm
14
+ def naive_wrap(string, line_width, font_size, options = {})
15
+ scan_pattern = options[:mode] == :character ? /./ : /\S+|\s+/
16
+
17
+ output = ""
18
+ string.lines.each do |line|
19
+ accumulated_width = 0
20
+ segments = line.scan(scan_pattern)
21
+
22
+ segments.each do |segment|
23
+ segment_width = string_width(segment, font_size,
24
+ :kerning => options[:kerning])
25
+
26
+ if (accumulated_width + segment_width).round > line_width.round
27
+ output = "#{output.sub(/[ \t]*\n?(\n*)\z/, "\n\\1")}"
28
+
29
+ if segment =~ /\s/
30
+ accumulated_width = 0
31
+ else
32
+ output << segment
33
+ accumulated_width = segment_width
34
+ end
35
+ else
36
+ output << segment
37
+ accumulated_width += segment_width
38
+ end
39
+ end
40
+ end
41
+
42
+ output
43
+ end
44
+
45
+ end
46
+ end
47
+ end